mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 562740, combine popup layout methods, fix menulist scrollbar position when list is larger that screen, r=roc
This commit is contained in:
parent
443b5d3dfe
commit
2fb544a731
@ -746,55 +746,9 @@ nsMenuFrame::DoLayout(nsBoxLayoutState& aState)
|
||||
// lay us out
|
||||
nsresult rv = nsBoxFrame::DoLayout(aState);
|
||||
|
||||
// layout the popup. First we need to get it.
|
||||
if (mPopupFrame) {
|
||||
PRBool sizeToPopup = IsSizedToPopup(mContent, PR_FALSE);
|
||||
// then get its preferred size
|
||||
nsSize prefSize = mPopupFrame->GetPrefSize(aState);
|
||||
nsSize minSize = mPopupFrame->GetMinSize(aState);
|
||||
nsSize maxSize = mPopupFrame->GetMaxSize(aState);
|
||||
|
||||
prefSize = BoundsCheck(minSize, prefSize, maxSize);
|
||||
|
||||
if (sizeToPopup)
|
||||
prefSize.width = mRect.width;
|
||||
|
||||
// if the pref size changed then set bounds to be the pref size
|
||||
PRBool sizeChanged = (mPopupFrame->PreferredSize() != prefSize);
|
||||
if (sizeChanged) {
|
||||
mPopupFrame->SetPreferredBounds(aState, nsRect(0,0,prefSize.width, prefSize.height));
|
||||
}
|
||||
|
||||
// if the menu has just been opened, or its size changed, position
|
||||
// the popup. The flag that the popup checks in the HasOpenChanged
|
||||
// method will get cleared in AdjustView which is called below.
|
||||
if (IsOpen() && (sizeChanged || mPopupFrame->HasOpenChanged()))
|
||||
mPopupFrame->SetPopupPosition(this, PR_FALSE);
|
||||
|
||||
// is the new size too small? Make sure we handle scrollbars correctly
|
||||
nsIBox* child = mPopupFrame->GetChildBox();
|
||||
|
||||
nsRect bounds(mPopupFrame->GetRect());
|
||||
|
||||
nsIScrollableFrame *scrollframe = do_QueryFrame(child);
|
||||
if (scrollframe &&
|
||||
scrollframe->GetScrollbarStyles().mVertical == NS_STYLE_OVERFLOW_AUTO) {
|
||||
if (bounds.height < prefSize.height) {
|
||||
// layout the child
|
||||
mPopupFrame->Layout(aState);
|
||||
|
||||
nsMargin scrollbars = scrollframe->GetActualScrollbarSizes();
|
||||
if (bounds.width < prefSize.width + scrollbars.left + scrollbars.right)
|
||||
{
|
||||
bounds.width += scrollbars.left + scrollbars.right;
|
||||
mPopupFrame->SetBounds(aState, bounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// layout the child
|
||||
mPopupFrame->Layout(aState);
|
||||
mPopupFrame->AdjustView();
|
||||
mPopupFrame->LayoutPopup(aState, this, sizeToPopup);
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
@ -369,43 +369,86 @@ nsMenuPopupFrame::IsLeaf() const
|
||||
}
|
||||
|
||||
void
|
||||
nsMenuPopupFrame::SetPreferredBounds(nsBoxLayoutState& aState,
|
||||
const nsRect& aRect)
|
||||
nsMenuPopupFrame::LayoutPopup(nsBoxLayoutState& aState, nsIFrame* aParentMenu, PRBool aSizedToPopup)
|
||||
{
|
||||
nsBox::SetBounds(aState, aRect, PR_FALSE);
|
||||
mPrefSize = aRect.Size();
|
||||
// if the popup is not open, only do layout if the menu is sized to the popup
|
||||
PRBool isOpen = IsOpen();
|
||||
if (!mGeneratedChildren || (!isOpen && !aSizedToPopup))
|
||||
return;
|
||||
|
||||
// get the preferred, minimum and maximum size. If the menu is sized to the
|
||||
// popup, then the popup's width is the menu's width.
|
||||
nsSize prefSize = GetPrefSize(aState);
|
||||
nsSize minSize = GetMinSize(aState);
|
||||
nsSize maxSize = GetMaxSize(aState);
|
||||
|
||||
if (aSizedToPopup) {
|
||||
prefSize.width = aParentMenu->GetRect().width;
|
||||
}
|
||||
prefSize = BoundsCheck(minSize, prefSize, maxSize);
|
||||
|
||||
// if the size changed then set the bounds to be the preferred size
|
||||
PRBool sizeChanged = (mPrefSize != prefSize);
|
||||
if (sizeChanged) {
|
||||
SetBounds(aState, nsRect(0, 0, prefSize.width, prefSize.height), PR_FALSE);
|
||||
mPrefSize = prefSize;
|
||||
}
|
||||
|
||||
if (isOpen) {
|
||||
SetPopupPosition(aParentMenu, PR_FALSE);
|
||||
}
|
||||
|
||||
nsRect bounds(GetRect());
|
||||
Layout(aState);
|
||||
|
||||
// if the width or height changed, readjust the popup position. This is a
|
||||
// special case for tooltips where the preferred height doesn't include the
|
||||
// real height for its inline element, but does once it is laid out.
|
||||
// This is bug 228673 which doesn't have a simple fix.
|
||||
if (!aParentMenu) {
|
||||
nsSize newsize = GetSize();
|
||||
if (newsize.width > bounds.width || newsize.height > bounds.height) {
|
||||
// the size after layout was larger than the preferred size,
|
||||
// so set the preferred size accordingly
|
||||
mPrefSize = newsize;
|
||||
if (isOpen) {
|
||||
SetPopupPosition(nsnull, PR_FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isOpen) {
|
||||
AdjustView();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsMenuPopupFrame::AdjustView()
|
||||
{
|
||||
if ((mPopupState == ePopupOpen || mPopupState == ePopupOpenAndVisible) &&
|
||||
mGeneratedChildren) {
|
||||
// if the popup has just opened, make sure the scrolled window is at 0,0
|
||||
if (mIsOpenChanged) {
|
||||
nsIBox* child = GetChildBox();
|
||||
nsIScrollableFrame *scrollframe = do_QueryFrame(child);
|
||||
if (scrollframe)
|
||||
scrollframe->ScrollTo(nsPoint(0,0), nsIScrollableFrame::INSTANT);
|
||||
}
|
||||
// if the popup has just opened, make sure the scrolled window is at 0,0
|
||||
if (mIsOpenChanged) {
|
||||
nsIBox* child = GetChildBox();
|
||||
nsIScrollableFrame *scrollframe = do_QueryFrame(child);
|
||||
if (scrollframe)
|
||||
scrollframe->ScrollTo(nsPoint(0,0), nsIScrollableFrame::INSTANT);
|
||||
}
|
||||
|
||||
nsIView* view = GetView();
|
||||
nsIViewManager* viewManager = view->GetViewManager();
|
||||
nsRect rect = GetRect();
|
||||
rect.x = rect.y = 0;
|
||||
viewManager->ResizeView(view, rect);
|
||||
viewManager->SetViewVisibility(view, nsViewVisibility_kShow);
|
||||
mPopupState = ePopupOpenAndVisible;
|
||||
nsIView* view = GetView();
|
||||
nsIViewManager* viewManager = view->GetViewManager();
|
||||
nsRect rect = GetRect();
|
||||
rect.x = rect.y = 0;
|
||||
viewManager->ResizeView(view, rect);
|
||||
viewManager->SetViewVisibility(view, nsViewVisibility_kShow);
|
||||
mPopupState = ePopupOpenAndVisible;
|
||||
|
||||
nsPresContext* pc = PresContext();
|
||||
nsContainerFrame::SyncFrameViewProperties(pc, this, nsnull, view, 0);
|
||||
nsPresContext* pc = PresContext();
|
||||
nsContainerFrame::SyncFrameViewProperties(pc, this, nsnull, view, 0);
|
||||
|
||||
// fire popupshown event when the state has changed
|
||||
if (mIsOpenChanged) {
|
||||
mIsOpenChanged = PR_FALSE;
|
||||
nsCOMPtr<nsIRunnable> event = new nsXULPopupShownEvent(GetContent(), pc);
|
||||
NS_DispatchToCurrentThread(event);
|
||||
}
|
||||
// fire popupshown event when the state has changed
|
||||
if (mIsOpenChanged) {
|
||||
mIsOpenChanged = PR_FALSE;
|
||||
nsCOMPtr<nsIRunnable> event = new nsXULPopupShownEvent(GetContent(), pc);
|
||||
NS_DispatchToCurrentThread(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,8 +199,10 @@ public:
|
||||
|
||||
virtual PRBool IsLeaf() const;
|
||||
|
||||
// AdjustView should be called by the parent frame after the popup has been
|
||||
// laid out, so that the view can be shown.
|
||||
// layout, position and display the popup as needed
|
||||
void LayoutPopup(nsBoxLayoutState& aState, nsIFrame* aParentMenu, PRBool aSizedToPopup);
|
||||
|
||||
// AdjustView is called by LayoutPopup to position and show the popup's view.
|
||||
void AdjustView();
|
||||
|
||||
nsIView* GetRootViewForPopup(nsIFrame* aStartFrame);
|
||||
@ -226,7 +228,6 @@ public:
|
||||
nsPopupType PopupType() const { return mPopupType; }
|
||||
PRBool IsMenu() { return mPopupType == ePopupTypeMenu; }
|
||||
PRBool IsOpen() { return mPopupState == ePopupOpen || mPopupState == ePopupOpenAndVisible; }
|
||||
PRBool HasOpenChanged() { return mIsOpenChanged; }
|
||||
|
||||
// returns true if the popup is in a content shell, or false for a popup in
|
||||
// a chrome shell
|
||||
@ -291,14 +292,6 @@ public:
|
||||
|
||||
nsIScrollableFrame* GetScrollFrame(nsIFrame* aStart);
|
||||
|
||||
// same as SetBounds except the preferred size mPrefSize is also set.
|
||||
void SetPreferredBounds(nsBoxLayoutState& aState, const nsRect& aRect);
|
||||
|
||||
// retrieve the last preferred size
|
||||
nsSize PreferredSize() { return mPrefSize; }
|
||||
// set the last preferred size
|
||||
void SetPreferredSize(nsSize aSize) { mPrefSize = aSize; }
|
||||
|
||||
// For a popup that should appear at the given anchor point, determine
|
||||
// the screen area that it is constrained by. This will be the available
|
||||
// area of the screen the popup should be displayed on. Content popups,
|
||||
@ -369,9 +362,6 @@ protected:
|
||||
// mRect in the case where the popup was resized because it was too large
|
||||
// for the screen. The preferred size mPrefSize holds the full size the popup
|
||||
// would be before resizing. Computations are performed using this size.
|
||||
// The parent frame is responsible for setting the preferred size using
|
||||
// SetPreferredBounds or SetPreferredSize before positioning the popup with
|
||||
// SetPopupPosition.
|
||||
nsSize mPrefSize;
|
||||
|
||||
// the position of the popup. The screen coordinates, if set to values other
|
||||
|
@ -155,54 +155,7 @@ nsPopupSetFrame::DoLayout(nsBoxLayoutState& aState)
|
||||
// lay out all of our currently open popups.
|
||||
for (nsFrameList::Enumerator e(mPopupList); !e.AtEnd(); e.Next()) {
|
||||
nsMenuPopupFrame* popupChild = static_cast<nsMenuPopupFrame*>(e.get());
|
||||
if (popupChild->IsOpen()) {
|
||||
// then get its preferred size
|
||||
nsSize prefSize = popupChild->GetPrefSize(aState);
|
||||
nsSize minSize = popupChild->GetMinSize(aState);
|
||||
nsSize maxSize = popupChild->GetMaxSize(aState);
|
||||
|
||||
prefSize = BoundsCheck(minSize, prefSize, maxSize);
|
||||
|
||||
popupChild->SetPreferredBounds(aState, nsRect(0,0,prefSize.width, prefSize.height));
|
||||
popupChild->SetPopupPosition(nsnull, PR_FALSE);
|
||||
|
||||
// is the new size too small? Make sure we handle scrollbars correctly
|
||||
nsIBox* child = popupChild->GetChildBox();
|
||||
|
||||
nsRect bounds(popupChild->GetRect());
|
||||
|
||||
nsIScrollableFrame *scrollframe = do_QueryFrame(child);
|
||||
if (scrollframe &&
|
||||
scrollframe->GetScrollbarStyles().mVertical == NS_STYLE_OVERFLOW_AUTO) {
|
||||
// if our pref height
|
||||
if (bounds.height < prefSize.height) {
|
||||
// layout the child
|
||||
popupChild->Layout(aState);
|
||||
|
||||
nsMargin scrollbars = scrollframe->GetActualScrollbarSizes();
|
||||
if (bounds.width < prefSize.width + scrollbars.left + scrollbars.right)
|
||||
{
|
||||
bounds.width += scrollbars.left + scrollbars.right;
|
||||
popupChild->SetBounds(aState, bounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// layout the child
|
||||
popupChild->Layout(aState);
|
||||
// if the width or height changed, readjust the popup position. This is a
|
||||
// special case for tooltips where the preferred height doesn't include the
|
||||
// real height for its inline element, but does once it is laid out.
|
||||
// This is bug 228673 which doesn't have a simple fix.
|
||||
if (popupChild->GetRect().width > bounds.width ||
|
||||
popupChild->GetRect().height > bounds.height) {
|
||||
// the size after layout was larger than the preferred size,
|
||||
// so set the preferred size accordingly
|
||||
popupChild->SetPreferredSize(popupChild->GetSize());
|
||||
popupChild->SetPopupPosition(nsnull, PR_FALSE);
|
||||
}
|
||||
popupChild->AdjustView();
|
||||
}
|
||||
popupChild->LayoutPopup(aState, nsnull, PR_FALSE);
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
@ -279,20 +279,17 @@ nsXULPopupManager::GetFrameOfTypeForContent(nsIContent* aContent,
|
||||
nsIAtom* aFrameType,
|
||||
PRBool aShouldFlush)
|
||||
{
|
||||
nsIDocument *document = aContent->GetCurrentDoc();
|
||||
if (document) {
|
||||
nsCOMPtr<nsIPresShell> presShell = document->GetPrimaryShell();
|
||||
if (presShell) {
|
||||
if (aShouldFlush)
|
||||
if (aShouldFlush) {
|
||||
nsIDocument *document = aContent->GetCurrentDoc();
|
||||
if (document) {
|
||||
nsCOMPtr<nsIPresShell> presShell = document->GetPrimaryShell();
|
||||
if (presShell)
|
||||
presShell->FlushPendingNotifications(Flush_Frames);
|
||||
|
||||
nsIFrame* frame = aContent->GetPrimaryFrame();
|
||||
if (frame && frame->GetType() == aFrameType)
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
nsIFrame* frame = aContent->GetPrimaryFrame();
|
||||
return (frame && frame->GetType() == aFrameType) ? frame : nsnull;
|
||||
}
|
||||
|
||||
nsMenuFrame*
|
||||
|
@ -82,9 +82,16 @@ function differentPressed()
|
||||
// now make sure that using a key scrolls the menu correctly
|
||||
gShowPopup = true;
|
||||
|
||||
for (let i = 0; i < 15; i++) {
|
||||
for (let i = 0; i < 65; i++) {
|
||||
list.appendItem("Item" + i, "item" + i);
|
||||
}
|
||||
list.open = true;
|
||||
is(list.getBoundingClientRect().width, list.firstChild.getBoundingClientRect().width,
|
||||
"menu and popup width match");
|
||||
ok(list.getBoundingClientRect().width > list.getItemAtIndex(0).getBoundingClientRect().width + 2,
|
||||
"menuitem width accounts for scrollbar");
|
||||
list.open = false;
|
||||
|
||||
list.menupopup.maxHeight = 100;
|
||||
list.open = true;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user