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 @@