diff --git a/accessible/tests/mochitest/events/test_scroll.xul b/accessible/tests/mochitest/events/test_scroll.xul
index 2fec8a662fd..5c560766d59 100644
--- a/accessible/tests/mochitest/events/test_scroll.xul
+++ b/accessible/tests/mochitest/events/test_scroll.xul
@@ -128,6 +128,7 @@
tabcontainer="tabbrowser-tabs"
flex="1"/>
+
diff --git a/accessible/tests/mochitest/relations/test_tabbrowser.xul b/accessible/tests/mochitest/relations/test_tabbrowser.xul
index 937ce7ef08e..6ec0a99f261 100644
--- a/accessible/tests/mochitest/relations/test_tabbrowser.xul
+++ b/accessible/tests/mochitest/relations/test_tabbrowser.xul
@@ -120,6 +120,7 @@
type="content-primary"
tabcontainer="tabbrowser-tabs"
flex="1"/>
+
diff --git a/accessible/tests/mochitest/tree/test_tabbrowser.xul b/accessible/tests/mochitest/tree/test_tabbrowser.xul
index 56ef5bd1a08..8eb738556a2 100644
--- a/accessible/tests/mochitest/tree/test_tabbrowser.xul
+++ b/accessible/tests/mochitest/tree/test_tabbrowser.xul
@@ -154,6 +154,7 @@
type="content-primary"
tabcontainer="tabbrowser-tabs"
flex="1"/>
+
diff --git a/browser/base/content/browser.css b/browser/base/content/browser.css
index 0a82ec3cc12..999a841bd5b 100644
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -481,7 +481,7 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
}
/* Remove the resizer from the statusbar compatibility shim */
-#status-bar > .statusbar-resizerpanel {
+#status-bar[hideresizer] > .statusbar-resizerpanel {
display: none;
}
diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
index d3f86f9e459..f5c19b43bf1 100644
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1241,6 +1241,9 @@ function BrowserStartup() {
document.documentElement.setAttribute("height", defaultHeight);
}
+ if (!gShowPageResizers)
+ document.getElementById("status-bar").setAttribute("hideresizer", "true");
+
if (!window.toolbar.visible) {
// adjust browser UI for popups
if (gURLBar) {
@@ -2751,6 +2754,7 @@ var PrintPreviewListener = {
var addonBar = document.getElementById("addon-bar");
this._chromeState.addonBarOpen = !addonBar.collapsed;
addonBar.collapsed = true;
+ gBrowser.updateWindowResizers();
this._chromeState.findOpen = gFindBarInitialized && !gFindBar.hidden;
if (gFindBarInitialized)
@@ -2767,8 +2771,10 @@ var PrintPreviewListener = {
if (this._chromeState.notificationsOpen)
gBrowser.getNotificationBox().notificationsHidden = false;
- if (this._chromeState.addonBarOpen)
+ if (this._chromeState.addonBarOpen) {
document.getElementById("addon-bar").collapsed = false;
+ gBrowser.updateWindowResizers();
+ }
if (this._chromeState.findOpen)
gFindBar.open();
@@ -4719,6 +4725,7 @@ function setToolbarVisibility(toolbar, isVisible) {
PlacesToolbarHelper.init();
BookmarksMenuButton.updatePosition();
+ gBrowser.updateWindowResizers();
#ifdef MENUBAR_CAN_AUTOHIDE
updateAppButtonDisplay();
@@ -8206,3 +8213,15 @@ let AddonsMgrListener = {
setToolbarVisibility(this.addonBar, false);
}
};
+
+XPCOMUtils.defineLazyGetter(window, "gShowPageResizers", function () {
+#ifdef XP_WIN
+ // Only show resizers on Windows 2000 and XP
+ let sysInfo = Components.classes["@mozilla.org/system-info;1"]
+ .getService(Components.interfaces.nsIPropertyBag2);
+ return parseFloat(sysInfo.getProperty("version")) < 6;
+#else
+ return false;
+#endif
+});
+
diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml
index 58f6e320417..272364f162d 100644
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -177,6 +177,18 @@
]]>
+
+
+
+
diff --git a/content/base/src/nsGkAtomList.h b/content/base/src/nsGkAtomList.h
index 910e48e4baa..50dabed30c5 100644
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -886,6 +886,7 @@ GK_ATOM(setter, "setter")
GK_ATOM(shape, "shape")
GK_ATOM(show, "show")
GK_ATOM(showcaret, "showcaret")
+GK_ATOM(showresizer, "showresizer")
GK_ATOM(simple, "simple")
GK_ATOM(single, "single")
GK_ATOM(size, "size")
diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp
index d906cb8525a..9cb2b4f4ef8 100644
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -784,6 +784,27 @@ nsHTMLScrollFrame::IsCollapsed(nsBoxLayoutState& aBoxLayoutState)
return PR_FALSE;
}
+// Return the if the scrollframe is for the root frame directly
+// inside a .
+static nsIContent*
+GetBrowserRoot(nsIContent* aContent)
+{
+ if (aContent) {
+ nsIDocument* doc = aContent->GetCurrentDoc();
+ nsPIDOMWindow* win = doc->GetWindow();
+ if (win) {
+ nsCOMPtr frameContent =
+ do_QueryInterface(win->GetFrameElementInternal());
+ if (frameContent &&
+ frameContent->NodeInfo()->Equals(nsGkAtoms::browser, kNameSpaceID_XUL))
+ return frameContent;
+ }
+ }
+
+ return nsnull;
+}
+
+
NS_IMETHODIMP
nsHTMLScrollFrame::Reflow(nsPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
@@ -813,11 +834,23 @@ nsHTMLScrollFrame::Reflow(nsPresContext* aPresContext,
reflowContents = NEEDS_REFLOW(mInner.mScrolledFrame);
reflowHScrollbar = NEEDS_REFLOW(mInner.mHScrollbarBox);
reflowVScrollbar = NEEDS_REFLOW(mInner.mVScrollbarBox);
- reflowScrollCorner = NEEDS_REFLOW(mInner.mScrollCornerBox);
+ reflowScrollCorner = NEEDS_REFLOW(mInner.mScrollCornerBox) ||
+ NEEDS_REFLOW(mInner.mResizerBox);
#undef NEEDS_REFLOW
}
+ if (mInner.mIsRoot) {
+ mInner.mCollapsedResizer = PR_TRUE;
+
+ nsIContent* browserRoot = GetBrowserRoot(mContent);
+ if (browserRoot) {
+ PRBool showResizer = browserRoot->HasAttr(kNameSpaceID_None, nsGkAtoms::showresizer);
+ reflowScrollCorner = showResizer == mInner.mCollapsedResizer;
+ mInner.mCollapsedResizer = !showResizer;
+ }
+ }
+
nsRect oldScrollAreaBounds = mInner.mScrollPort;
nsRect oldScrolledAreaBounds =
mInner.mScrolledFrame->GetScrollableOverflowRectRelativeToParent();
@@ -1326,6 +1359,7 @@ nsGfxScrollFrameInner::nsGfxScrollFrameInner(nsContainerFrame* aOuter,
mVScrollbarBox(nsnull),
mScrolledFrame(nsnull),
mScrollCornerBox(nsnull),
+ mResizerBox(nsnull),
mOuter(aOuter),
mAsyncScroll(nsnull),
mDestination(0, 0),
@@ -1348,7 +1382,8 @@ nsGfxScrollFrameInner::nsGfxScrollFrameInner(nsContainerFrame* aOuter,
mPostedReflowCallback(PR_FALSE),
mMayHaveDirtyFixedChildren(PR_FALSE),
mUpdateScrollbarAttributes(PR_FALSE),
- mScrollingActive(PR_FALSE)
+ mScrollingActive(PR_FALSE),
+ mCollapsedResizer(PR_FALSE)
{
// lookup if we're allowed to overlap the content from the look&feel object
PRBool canOverlap;
@@ -1755,7 +1790,7 @@ nsGfxScrollFrameInner::AppendScrollPartsTo(nsDisplayListBuilder* aBuild
PRBool hasResizer = HasResizer();
for (nsIFrame* kid = mOuter->GetFirstChild(nsnull); kid; kid = kid->GetNextSibling()) {
if (kid != mScrolledFrame) {
- if (kid == mScrollCornerBox && hasResizer) {
+ if (kid == mResizerBox && hasResizer) {
// skip the resizer as this will be drawn later on top of the scrolled content
continue;
}
@@ -1850,14 +1885,14 @@ nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder* aBuilder,
// scrolled content in the Content() list.
// This ensures that the resizer appears above the content and the mouse can
// still target the resizer even when scrollbars are hidden.
- if (HasResizer() && mScrollCornerBox) {
- rv = mOuter->BuildDisplayListForChild(aBuilder, mScrollCornerBox, aDirtyRect, scrollParts,
+ if (HasResizer() && mResizerBox) {
+ rv = mOuter->BuildDisplayListForChild(aBuilder, mResizerBox, aDirtyRect, scrollParts,
nsIFrame::DISPLAY_CHILD_FORCE_STACKING_CONTEXT);
NS_ENSURE_SUCCESS(rv, rv);
// DISPLAY_CHILD_FORCE_STACKING_CONTEXT puts everything into the
// PositionedDescendants list.
::AppendToTop(aBuilder, aLists.Content(),
- scrollParts.PositionedDescendants(), mScrollCornerBox,
+ scrollParts.PositionedDescendants(), mResizerBox,
createLayersForScrollbars);
}
@@ -2130,6 +2165,7 @@ nsGfxScrollFrameInner::ReloadChildFrames()
mHScrollbarBox = nsnull;
mVScrollbarBox = nsnull;
mScrollCornerBox = nsnull;
+ mResizerBox = nsnull;
nsIFrame* frame = mOuter->GetFirstChild(nsnull);
while (frame) {
@@ -2149,6 +2185,9 @@ nsGfxScrollFrameInner::ReloadChildFrames()
NS_ASSERTION(!mVScrollbarBox, "Found multiple vertical scrollbars?");
mVScrollbarBox = frame;
}
+ } else if (content->Tag() == nsGkAtoms::resizer) {
+ NS_ASSERTION(!mResizerBox, "Found multiple resizers");
+ mResizerBox = frame;
} else {
// probably a scrollcorner
NS_ASSERTION(!mScrollCornerBox, "Found multiple scrollcorners");
@@ -2250,7 +2289,7 @@ nsGfxScrollFrameInner::CreateAnonymousContent(nsTArray& aElements)
kNameSpaceID_XUL);
NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
- NS_TrustedNewXULElement(getter_AddRefs(mScrollCornerContent), nodeInfo.forget());
+ NS_TrustedNewXULElement(getter_AddRefs(mResizerContent), nodeInfo.forget());
nsAutoString dir;
switch (resizeStyle) {
@@ -2271,16 +2310,26 @@ nsGfxScrollFrameInner::CreateAnonymousContent(nsTArray& aElements)
default:
NS_WARNING("only resizable types should have resizers");
}
- mScrollCornerContent->SetAttr(kNameSpaceID_None, nsGkAtoms::dir, dir, PR_FALSE);
- mScrollCornerContent->SetAttr(kNameSpaceID_None, nsGkAtoms::element,
- NS_LITERAL_STRING("_parent"), PR_FALSE);
- mScrollCornerContent->SetAttr(kNameSpaceID_None, nsGkAtoms::clickthrough,
+ mResizerContent->SetAttr(kNameSpaceID_None, nsGkAtoms::dir, dir, PR_FALSE);
+
+ if (mIsRoot) {
+ nsIContent* browserRoot = GetBrowserRoot(mOuter->GetContent());
+ mCollapsedResizer = !(browserRoot &&
+ browserRoot->HasAttr(kNameSpaceID_None, nsGkAtoms::showresizer));
+ }
+ else {
+ mResizerContent->SetAttr(kNameSpaceID_None, nsGkAtoms::element,
+ NS_LITERAL_STRING("_parent"), PR_FALSE);
+ }
+
+ mResizerContent->SetAttr(kNameSpaceID_None, nsGkAtoms::clickthrough,
NS_LITERAL_STRING("always"), PR_FALSE);
- if (!aElements.AppendElement(mScrollCornerContent))
+ if (!aElements.AppendElement(mResizerContent))
return NS_ERROR_OUT_OF_MEMORY;
}
- else if (canHaveHorizontal && canHaveVertical) {
+
+ if (canHaveHorizontal && canHaveVertical) {
nodeInfo = nodeInfoManager->GetNodeInfo(nsGkAtoms::scrollcorner, nsnull,
kNameSpaceID_XUL);
NS_TrustedNewXULElement(getter_AddRefs(mScrollCornerContent), nodeInfo.forget());
@@ -2298,6 +2347,7 @@ nsGfxScrollFrameInner::AppendAnonymousContentTo(nsBaseContentList& aElements,
aElements.MaybeAppendElement(mHScrollbarContent);
aElements.MaybeAppendElement(mVScrollbarContent);
aElements.MaybeAppendElement(mScrollCornerContent);
+ aElements.MaybeAppendElement(mResizerContent);
}
void
@@ -2307,6 +2357,7 @@ nsGfxScrollFrameInner::Destroy()
nsContentUtils::DestroyAnonymousContent(&mHScrollbarContent);
nsContentUtils::DestroyAnonymousContent(&mVScrollbarContent);
nsContentUtils::DestroyAnonymousContent(&mScrollCornerContent);
+ nsContentUtils::DestroyAnonymousContent(&mResizerContent);
if (mPostedReflowCallback) {
mOuter->PresContext()->PresShell()->CancelReflowCallback(this);
@@ -3046,8 +3097,8 @@ nsGfxScrollFrameInner::AdjustScrollbarRectForResizer(
// if a content resizer is present, use its size. Otherwise, check if the
// widget has a resizer.
nsRect resizerRect;
- if (aHasResizer && mScrollCornerBox) {
- resizerRect = mScrollCornerBox->GetRect();
+ if (aHasResizer) {
+ resizerRect = mResizerBox->GetRect();
}
else {
nsPoint offset;
@@ -3083,32 +3134,18 @@ nsGfxScrollFrameInner::LayoutScrollbars(nsBoxLayoutState& aState,
PRBool scrollbarOnLeft = !IsScrollbarOnRight();
// place the scrollcorner
- if (mScrollCornerBox) {
- NS_PRECONDITION(mScrollCornerBox->IsBoxFrame(), "Must be a box frame!");
-
- // if a resizer is present, get its size
- nsSize resizerSize;
- if (HasResizer()) {
- // just assume a default size of 15 pixels
- nscoord defaultSize = nsPresContext::CSSPixelsToAppUnits(15);
- resizerSize.width =
- mVScrollbarBox ? mVScrollbarBox->GetMinSize(aState).width : defaultSize;
- resizerSize.height =
- mHScrollbarBox ? mHScrollbarBox->GetMinSize(aState).height : defaultSize;
- }
- else {
- resizerSize = nsSize(0, 0);
- }
+ if (mScrollCornerBox || mResizerBox) {
+ NS_PRECONDITION(!mScrollCornerBox || mScrollCornerBox->IsBoxFrame(), "Must be a box frame!");
nsRect r(0, 0, 0, 0);
if (aContentArea.x != mScrollPort.x || scrollbarOnLeft) {
// scrollbar (if any) on left
r.x = aContentArea.x;
- r.width = PR_MAX(resizerSize.width, mScrollPort.x - aContentArea.x);
+ r.width = mScrollPort.x - aContentArea.x;
NS_ASSERTION(r.width >= 0, "Scroll area should be inside client rect");
} else {
// scrollbar (if any) on right
- r.width = PR_MAX(resizerSize.width, aContentArea.XMost() - mScrollPort.XMost());
+ r.width = aContentArea.XMost() - mScrollPort.XMost();
r.x = aContentArea.XMost() - r.width;
NS_ASSERTION(r.width >= 0, "Scroll area should be inside client rect");
}
@@ -3116,11 +3153,41 @@ nsGfxScrollFrameInner::LayoutScrollbars(nsBoxLayoutState& aState,
NS_ERROR("top scrollbars not supported");
} else {
// scrollbar (if any) on bottom
- r.height = PR_MAX(resizerSize.height, aContentArea.YMost() - mScrollPort.YMost());
+ r.height = aContentArea.YMost() - mScrollPort.YMost();
r.y = aContentArea.YMost() - r.height;
NS_ASSERTION(r.height >= 0, "Scroll area should be inside client rect");
}
- LayoutAndInvalidate(aState, mScrollCornerBox, r, PR_FALSE);
+
+ if (mScrollCornerBox) {
+ LayoutAndInvalidate(aState, mScrollCornerBox, r, PR_FALSE);
+ }
+
+ if (hasResizer) {
+ // if a resizer is present, get its size. Assume a default size of 15 pixels.
+ nsSize resizerSize;
+ nscoord defaultSize = nsPresContext::CSSPixelsToAppUnits(15);
+ resizerSize.width =
+ mVScrollbarBox ? mVScrollbarBox->GetMinSize(aState).width : defaultSize;
+ if (resizerSize.width > r.width) {
+ r.width = resizerSize.width;
+ if (aContentArea.x == mScrollPort.x && !scrollbarOnLeft)
+ r.x = aContentArea.XMost() - r.width;
+ }
+
+ resizerSize.height =
+ mHScrollbarBox ? mHScrollbarBox->GetMinSize(aState).height : defaultSize;
+ if (resizerSize.height > r.height) {
+ r.height = resizerSize.height;
+ if (aContentArea.y == mScrollPort.y)
+ r.y = aContentArea.YMost() - r.height;
+ }
+
+ LayoutAndInvalidate(aState, mResizerBox, r, PR_FALSE);
+ }
+ else if (mResizerBox) {
+ // otherwise lay out the resizer with an empty rectangle
+ LayoutAndInvalidate(aState, mResizerBox, nsRect(), PR_FALSE);
+ }
}
nsPresContext* presContext = mScrolledFrame->PresContext();
diff --git a/layout/generic/nsGfxScrollFrame.h b/layout/generic/nsGfxScrollFrame.h
index 2003bb4ce3c..d7d4004db9c 100644
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -230,9 +230,7 @@ public:
void AdjustScrollbarRectForResizer(nsIFrame* aFrame, nsPresContext* aPresContext,
nsRect& aRect, PRBool aHasResizer, PRBool aVertical);
// returns true if a resizer should be visible
- PRBool HasResizer() {
- return mScrollCornerContent && mScrollCornerContent->Tag() == nsGkAtoms::resizer;
- }
+ PRBool HasResizer() { return mResizerBox && !mCollapsedResizer; }
void LayoutScrollbars(nsBoxLayoutState& aState,
const nsRect& aContentArea,
const nsRect& aOldScrollArea);
@@ -245,6 +243,7 @@ public:
nsCOMPtr mHScrollbarContent;
nsCOMPtr mVScrollbarContent;
nsCOMPtr mScrollCornerContent;
+ nsCOMPtr mResizerContent;
nsRevocableEventPtr mScrollEvent;
nsRevocableEventPtr mAsyncScrollPortEvent;
@@ -253,6 +252,7 @@ public:
nsIBox* mVScrollbarBox;
nsIFrame* mScrolledFrame;
nsIBox* mScrollCornerBox;
+ nsIBox* mResizerBox;
nsContainerFrame* mOuter;
AsyncScroll* mAsyncScroll;
nsTArray mListeners;
@@ -305,6 +305,8 @@ public:
// If true, scrollbars are stacked on the top of the display list and can
// float above the content as a result
PRPackedBool mScrollbarsCanOverlapContent:1;
+ // If true, the resizer is collapsed and not displayed
+ PRPackedBool mCollapsedResizer:1;
};
/**
diff --git a/layout/generic/nsSubDocumentFrame.cpp b/layout/generic/nsSubDocumentFrame.cpp
index f89aa72c1be..beb656f32c1 100644
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -699,6 +699,13 @@ nsSubDocumentFrame::AttributeChanged(PRInt32 aNameSpaceID,
}
}
}
+ else if (aAttribute == nsGkAtoms::showresizer) {
+ nsIFrame* rootFrame = GetSubdocumentRootFrame();
+ if (rootFrame) {
+ rootFrame->PresContext()->PresShell()->
+ FrameNeedsReflow(rootFrame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
+ }
+ }
else if (aAttribute == nsGkAtoms::type) {
if (!mFrameLoader)
return NS_OK;
diff --git a/layout/style/ua.css b/layout/style/ua.css
index 99a48b7bce2..3620682461c 100644
--- a/layout/style/ua.css
+++ b/layout/style/ua.css
@@ -167,6 +167,7 @@
*|*::-moz-viewport-scroll {
overflow: auto;
+ resize: both;
}
*|*::-moz-column-content {
diff --git a/layout/xul/base/src/nsResizerFrame.cpp b/layout/xul/base/src/nsResizerFrame.cpp
index 04d89dac2b8..f77978ac7a5 100644
--- a/layout/xul/base/src/nsResizerFrame.cpp
+++ b/layout/xul/base/src/nsResizerFrame.cpp
@@ -361,8 +361,14 @@ nsResizerFrame::GetContentToResize(nsIPresShell* aPresShell, nsIBaseWindow** aWi
type == nsIDocShellTreeItem::typeChrome);
}
- if (!isChromeShell)
- return nsnull;
+ if (!isChromeShell) {
+ // don't allow resizers in content shells, except for the viewport
+ // scrollbar which doesn't have a parent
+ nsIContent* nonNativeAnon = mContent->FindFirstNonNativeAnonymous();
+ if (nonNativeAnon && !nonNativeAnon->GetParent()) {
+ return nsnull;
+ }
+ }
// get the document and the window - should this be cached?
nsPIDOMWindow *domWindow = aPresShell->GetDocument()->GetWindow();
diff --git a/toolkit/content/widgets/browser.xml b/toolkit/content/widgets/browser.xml
index bceb80e7563..d9b9e744b74 100644
--- a/toolkit/content/widgets/browser.xml
+++ b/toolkit/content/widgets/browser.xml
@@ -362,6 +362,12 @@
onget="return this.contentDocument.nodePrincipal;"
readonly="true"/>
+
+
Components.classes['@mozilla.org/preferences-service;1']
.getService(Components.interfaces.nsIPrefService)
diff --git a/toolkit/content/widgets/resizer.xml b/toolkit/content/widgets/resizer.xml
index 8f51381901e..38a7eed3ee4 100644
--- a/toolkit/content/widgets/resizer.xml
+++ b/toolkit/content/widgets/resizer.xml
@@ -10,6 +10,11 @@