Bug 489303, show resizer when statusbar is hidden, r=roc,gavin a=blocking

This commit is contained in:
Neil Deakin 2011-01-17 09:35:32 -05:00
parent b559352e18
commit 2672504f59
15 changed files with 180 additions and 43 deletions

View File

@ -128,6 +128,7 @@
tabcontainer="tabbrowser-tabs"
flex="1"/>
</vbox>
<toolbar id="addon-bar"/>
</hbox>
</window>

View File

@ -120,6 +120,7 @@
type="content-primary"
tabcontainer="tabbrowser-tabs"
flex="1"/>
<toolbar id="addon-bar"/>
</vbox>
</window>

View File

@ -154,6 +154,7 @@
type="content-primary"
tabcontainer="tabbrowser-tabs"
flex="1"/>
<toolbar id="addon-bar"/>
</vbox>
</window>

View File

@ -506,7 +506,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;
}

View File

@ -1264,6 +1264,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) {
@ -2776,6 +2779,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)
@ -2792,8 +2796,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();
@ -4767,6 +4773,7 @@ function setToolbarVisibility(toolbar, isVisible) {
PlacesToolbarHelper.init();
BookmarksMenuButton.updatePosition();
gBrowser.updateWindowResizers();
#ifdef MENUBAR_CAN_AUTOHIDE
updateAppButtonDisplay();
@ -8329,3 +8336,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
});

View File

@ -177,6 +177,18 @@
]]></getter>
</property>
<method name="updateWindowResizers">
<body><![CDATA[
if (!window.gShowPageResizers)
return;
var show = document.getElementById("addon-bar").collapsed;
for (let i = 0; i < this.browsers.length; i++) {
this.browsers[i].showWindowResizer = show;
}
]]></body>
</method>
<method name="pinTab">
<parameter name="aTab"/>
<body><![CDATA[
@ -1236,6 +1248,11 @@
b.setAttribute("message", "true");
b.setAttribute("contextmenu", this.getAttribute("contentcontextmenu"));
b.setAttribute("tooltip", this.getAttribute("contenttooltip"));
if (window.gShowPageResizers && document.getElementById("addon-bar").collapsed) {
b.setAttribute("showresizer", "true");
}
if (this.hasAttribute("autocompletepopup"))
b.setAttribute("autocompletepopup", this.getAttribute("autocompletepopup"));
b.setAttribute("autoscrollpopup", this._autoScrollPopup.id);
@ -2429,6 +2446,7 @@
this.appendChild(this._autoScrollPopup);
this.mCurrentBrowser.setAttribute("autoscrollpopup", this._autoScrollPopup.id);
this.mCurrentBrowser.droppedLinkHandler = handleDroppedLink;
this.updateWindowResizers();
]]>
</constructor>

View File

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

View File

@ -784,6 +784,27 @@ nsHTMLScrollFrame::IsCollapsed(nsBoxLayoutState& aBoxLayoutState)
return PR_FALSE;
}
// Return the <browser> if the scrollframe is for the root frame directly
// inside a <browser>.
static nsIContent*
GetBrowserRoot(nsIContent* aContent)
{
if (aContent) {
nsIDocument* doc = aContent->GetCurrentDoc();
nsPIDOMWindow* win = doc->GetWindow();
if (win) {
nsCOMPtr<nsIContent> 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();
@ -1325,6 +1358,7 @@ nsGfxScrollFrameInner::nsGfxScrollFrameInner(nsContainerFrame* aOuter,
mVScrollbarBox(nsnull),
mScrolledFrame(nsnull),
mScrollCornerBox(nsnull),
mResizerBox(nsnull),
mOuter(aOuter),
mAsyncScroll(nsnull),
mDestination(0, 0),
@ -1346,7 +1380,8 @@ nsGfxScrollFrameInner::nsGfxScrollFrameInner(nsContainerFrame* aOuter,
mVerticalOverflow(PR_FALSE),
mPostedReflowCallback(PR_FALSE),
mMayHaveDirtyFixedChildren(PR_FALSE),
mUpdateScrollbarAttributes(PR_FALSE)
mUpdateScrollbarAttributes(PR_FALSE),
mCollapsedResizer(PR_FALSE)
{
// lookup if we're allowed to overlap the content from the look&feel object
PRBool canOverlap;
@ -1768,7 +1803,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;
}
@ -1872,14 +1907,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);
}
@ -2152,6 +2187,7 @@ nsGfxScrollFrameInner::ReloadChildFrames()
mHScrollbarBox = nsnull;
mVScrollbarBox = nsnull;
mScrollCornerBox = nsnull;
mResizerBox = nsnull;
nsIFrame* frame = mOuter->GetFirstChild(nsnull);
while (frame) {
@ -2171,6 +2207,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");
@ -2272,7 +2311,7 @@ nsGfxScrollFrameInner::CreateAnonymousContent(nsTArray<nsIContent*>& 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) {
@ -2293,16 +2332,26 @@ nsGfxScrollFrameInner::CreateAnonymousContent(nsTArray<nsIContent*>& 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());
@ -2320,6 +2369,7 @@ nsGfxScrollFrameInner::AppendAnonymousContentTo(nsBaseContentList& aElements,
aElements.MaybeAppendElement(mHScrollbarContent);
aElements.MaybeAppendElement(mVScrollbarContent);
aElements.MaybeAppendElement(mScrollCornerContent);
aElements.MaybeAppendElement(mResizerContent);
}
void
@ -2329,6 +2379,7 @@ nsGfxScrollFrameInner::Destroy()
nsContentUtils::DestroyAnonymousContent(&mHScrollbarContent);
nsContentUtils::DestroyAnonymousContent(&mVScrollbarContent);
nsContentUtils::DestroyAnonymousContent(&mScrollCornerContent);
nsContentUtils::DestroyAnonymousContent(&mResizerContent);
if (mPostedReflowCallback) {
mOuter->PresContext()->PresShell()->CancelReflowCallback(this);
@ -3068,8 +3119,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;
@ -3105,32 +3156,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");
}
@ -3138,11 +3175,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();

View File

@ -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);
@ -246,6 +244,7 @@ public:
nsCOMPtr<nsIContent> mHScrollbarContent;
nsCOMPtr<nsIContent> mVScrollbarContent;
nsCOMPtr<nsIContent> mScrollCornerContent;
nsCOMPtr<nsIContent> mResizerContent;
nsRevocableEventPtr<ScrollEvent> mScrollEvent;
nsRevocableEventPtr<AsyncScrollPortEvent> mAsyncScrollPortEvent;
@ -254,6 +253,7 @@ public:
nsIBox* mVScrollbarBox;
nsIFrame* mScrolledFrame;
nsIBox* mScrollCornerBox;
nsIBox* mResizerBox;
nsContainerFrame* mOuter;
AsyncScroll* mAsyncScroll;
nsTArray<nsIScrollPositionListener*> mListeners;
@ -306,6 +306,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;
};
/**

View File

@ -741,6 +741,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;

View File

@ -1,5 +1,5 @@
toolkit.jar:
res/ua.css (ua.css)
* res/ua.css (ua.css)
res/html.css (html.css)
res/quirk.css (quirk.css)
res/viewsource.css (viewsource.css)

View File

@ -167,6 +167,9 @@
*|*::-moz-viewport-scroll {
overflow: auto;
%ifdef XP_WIN
resize: both;
%endif
}
*|*::-moz-column-content {

View File

@ -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();

View File

@ -362,6 +362,12 @@
onget="return this.contentDocument.nodePrincipal;"
readonly="true"/>
<property name="showWindowResizer"
onset="if (val) this.setAttribute('showresizer', 'true');
else this.removeAttribute('showresizer');
return val;"
onget="return this.getAttribute('showresizer') == 'true';"/>
<field name="mPrefs" readonly="true">
Components.classes['@mozilla.org/preferences-service;1']
.getService(Components.interfaces.nsIPrefService)

View File

@ -10,6 +10,11 @@
<implementation>
<constructor>
<![CDATA[
// don't do this for viewport resizers; causes a crash related to
// bugs 563665 and 581536 otherwise
if (this.parentNode == this.ownerDocument.documentElement)
return;
// if the direction is rtl, set the rtl attribute so that the
// stylesheet can use this to make the cursor appear properly
var direction = window.getComputedStyle(this, "").direction;