зеркало из https://github.com/mozilla/pjs.git
Back out bug 575294, bug 726264. (cset 1727de7d26ec, 6bcea3a628d8, 011c1c8e9cc7, 0be261a5042b, d51338c5cd0c)
This commit is contained in:
Родитель
430109553c
Коммит
57f80232ce
|
@ -927,21 +927,16 @@ nsFocusManager::WindowHidden(nsIDOMWindow* aWindow)
|
|||
nsIContent* oldFocusedContent = mFocusedContent;
|
||||
mFocusedContent = nsnull;
|
||||
|
||||
nsCOMPtr<nsIDocShell> focusedDocShell = mFocusedWindow->GetDocShell();
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
focusedDocShell->GetPresShell(getter_AddRefs(presShell));
|
||||
|
||||
if (oldFocusedContent && oldFocusedContent->IsInDoc()) {
|
||||
NotifyFocusStateChange(oldFocusedContent,
|
||||
mFocusedWindow->ShouldShowFocusRing(),
|
||||
false);
|
||||
window->UpdateCommands(NS_LITERAL_STRING("focus"));
|
||||
|
||||
SendFocusOrBlurEvent(NS_BLUR_CONTENT, presShell,
|
||||
oldFocusedContent->GetCurrentDoc(),
|
||||
oldFocusedContent, 1, false);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShell> focusedDocShell = mFocusedWindow->GetDocShell();
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
focusedDocShell->GetPresShell(getter_AddRefs(presShell));
|
||||
|
||||
nsIMEStateManager::OnTextStateBlur(nsnull, nsnull);
|
||||
if (presShell) {
|
||||
nsIMEStateManager::OnChangeFocus(presShell->GetPresContext(), nsnull,
|
||||
|
|
|
@ -116,7 +116,7 @@ NS_IMPL_ISUPPORTS1(nsComboButtonListener,
|
|||
nsIDOMEventListener)
|
||||
|
||||
// static class data member for Bug 32920
|
||||
nsComboboxControlFrame* nsComboboxControlFrame::sFocused = nsnull;
|
||||
nsComboboxControlFrame * nsComboboxControlFrame::mFocused = nsnull;
|
||||
|
||||
nsIFrame*
|
||||
NS_NewComboboxControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, PRUint32 aStateFlags)
|
||||
|
@ -279,18 +279,19 @@ static PRInt32 gReflowInx = -1;
|
|||
//------------------------------------------------------
|
||||
|
||||
nsComboboxControlFrame::nsComboboxControlFrame(nsStyleContext* aContext)
|
||||
: nsBlockFrame(aContext)
|
||||
, mDisplayFrame(nsnull)
|
||||
, mButtonFrame(nsnull)
|
||||
, mDropdownFrame(nsnull)
|
||||
, mListControlFrame(nsnull)
|
||||
, mDisplayWidth(0)
|
||||
, mRecentSelectedIndex(NS_SKIP_NOTIFY_INDEX)
|
||||
, mDisplayedIndex(-1)
|
||||
, mDroppedDown(false)
|
||||
, mInRedisplayText(false)
|
||||
, mDelayedShowDropDown(false)
|
||||
: nsBlockFrame(aContext),
|
||||
mDisplayWidth(0)
|
||||
{
|
||||
mListControlFrame = nsnull;
|
||||
mDroppedDown = false;
|
||||
mDisplayFrame = nsnull;
|
||||
mButtonFrame = nsnull;
|
||||
mDropdownFrame = nsnull;
|
||||
|
||||
mInRedisplayText = false;
|
||||
|
||||
mRecentSelectedIndex = NS_SKIP_NOTIFY_INDEX;
|
||||
|
||||
REFLOW_COUNTER_INIT()
|
||||
}
|
||||
|
||||
|
@ -324,22 +325,15 @@ nsComboboxControlFrame::CreateAccessible()
|
|||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
void
|
||||
nsComboboxControlFrame::SetFocus(bool aOn, bool aRepaint)
|
||||
{
|
||||
nsWeakFrame weakFrame(this);
|
||||
if (aOn) {
|
||||
nsListControlFrame::ComboboxFocusSet();
|
||||
sFocused = this;
|
||||
if (mDelayedShowDropDown) {
|
||||
ShowDropDown(true); // might destroy us
|
||||
if (!weakFrame.IsAlive()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
mFocused = this;
|
||||
} else {
|
||||
sFocused = nsnull;
|
||||
mDelayedShowDropDown = false;
|
||||
mFocused = nsnull;
|
||||
if (mDroppedDown) {
|
||||
mListControlFrame->ComboboxFinish(mDisplayedIndex); // might destroy us
|
||||
if (!weakFrame.IsAlive()) {
|
||||
|
@ -449,44 +443,6 @@ nsComboboxControlFrame::ShowList(bool aShowList)
|
|||
return weakFrame.IsAlive();
|
||||
}
|
||||
|
||||
class nsResizeDropdownAtFinalPosition
|
||||
: public nsIReflowCallback, public nsRunnable
|
||||
{
|
||||
public:
|
||||
nsResizeDropdownAtFinalPosition(nsComboboxControlFrame* aFrame)
|
||||
: mFrame(aFrame)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsResizeDropdownAtFinalPosition);
|
||||
}
|
||||
~nsResizeDropdownAtFinalPosition()
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsResizeDropdownAtFinalPosition);
|
||||
}
|
||||
|
||||
virtual bool ReflowFinished()
|
||||
{
|
||||
Run();
|
||||
NS_RELEASE_THIS();
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void ReflowCallbackCanceled()
|
||||
{
|
||||
NS_RELEASE_THIS();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP Run()
|
||||
{
|
||||
if (mFrame.IsAlive()) {
|
||||
static_cast<nsComboboxControlFrame*>(mFrame.GetFrame())->
|
||||
AbsolutelyPositionDropDown();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsWeakFrame mFrame;
|
||||
};
|
||||
|
||||
nsresult
|
||||
nsComboboxControlFrame::ReflowDropdown(nsPresContext* aPresContext,
|
||||
const nsHTMLReflowState& aReflowState)
|
||||
|
@ -580,166 +536,49 @@ nsComboboxControlFrame::GetCSSTransformTranslation()
|
|||
return translation;
|
||||
}
|
||||
|
||||
class nsAsyncRollup : public nsRunnable
|
||||
{
|
||||
public:
|
||||
nsAsyncRollup(nsComboboxControlFrame* aFrame) : mFrame(aFrame) {}
|
||||
NS_IMETHODIMP Run()
|
||||
{
|
||||
if (mFrame.IsAlive()) {
|
||||
static_cast<nsComboboxControlFrame*>(mFrame.GetFrame())
|
||||
->RollupFromList();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
nsWeakFrame mFrame;
|
||||
};
|
||||
|
||||
class nsAsyncResize : public nsRunnable
|
||||
{
|
||||
public:
|
||||
nsAsyncResize(nsComboboxControlFrame* aFrame) : mFrame(aFrame) {}
|
||||
NS_IMETHODIMP Run()
|
||||
{
|
||||
if (mFrame.IsAlive()) {
|
||||
nsComboboxControlFrame* combo =
|
||||
static_cast<nsComboboxControlFrame*>(mFrame.GetFrame());
|
||||
static_cast<nsListControlFrame*>(combo->mDropdownFrame)->
|
||||
SetSuppressScrollbarUpdate(true);
|
||||
nsCOMPtr<nsIPresShell> shell = mFrame->PresContext()->PresShell();
|
||||
shell->FrameNeedsReflow(combo->mDropdownFrame, nsIPresShell::eResize,
|
||||
NS_FRAME_IS_DIRTY);
|
||||
shell->FlushPendingNotifications(Flush_Layout);
|
||||
if (mFrame.IsAlive()) {
|
||||
combo = static_cast<nsComboboxControlFrame*>(mFrame.GetFrame());
|
||||
static_cast<nsListControlFrame*>(combo->mDropdownFrame)->
|
||||
SetSuppressScrollbarUpdate(false);
|
||||
if (combo->mDelayedShowDropDown) {
|
||||
combo->ShowDropDown(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
nsWeakFrame mFrame;
|
||||
};
|
||||
|
||||
void
|
||||
nsComboboxControlFrame::GetAvailableDropdownSpace(nscoord* aAbove,
|
||||
nscoord* aBelow,
|
||||
nsPoint* aTranslation)
|
||||
nsComboboxControlFrame::AbsolutelyPositionDropDown()
|
||||
{
|
||||
// Note: At first glance, it appears that you could simply get the absolute
|
||||
// bounding box for the dropdown list by first getting its view, then getting
|
||||
// the view's nsIWidget, then asking the nsIWidget for its AbsoluteBounds.
|
||||
// The problem with this approach, is that the dropdown lists y location can
|
||||
// change based on whether the dropdown is placed below or above the display
|
||||
// frame. The approach, taken here is to get the absolute position of the
|
||||
// display frame and use its location to determine if the dropdown will go
|
||||
// offscreen.
|
||||
// Position the dropdown list. It is positioned below the display frame if there is enough
|
||||
// room on the screen to display the entire list. Otherwise it is placed above the display
|
||||
// frame.
|
||||
|
||||
// Note: As first glance, it appears that you could simply get the absolute bounding box for the
|
||||
// dropdown list by first getting its view, then getting the view's nsIWidget, then asking the nsIWidget
|
||||
// for it's AbsoluteBounds. The problem with this approach, is that the dropdown lists y location can
|
||||
// change based on whether the dropdown is placed below or above the display frame.
|
||||
// The approach, taken here is to get use the absolute position of the display frame and use it's location
|
||||
// to determine if the dropdown will go offscreen.
|
||||
|
||||
// Normal frame geometry (eg GetOffsetTo, mRect) doesn't include transforms.
|
||||
// In the special case that our transform is only a 2D translation we
|
||||
// introduce this hack so that the dropdown will show up in the right place.
|
||||
*aTranslation = GetCSSTransformTranslation();
|
||||
*aAbove = 0;
|
||||
*aBelow = 0;
|
||||
|
||||
nsRect thisScreenRect = GetScreenRectInAppUnits();
|
||||
nsRect screen = nsFormControlFrame::GetUsableScreenRect(PresContext());
|
||||
nscoord dropdownY = thisScreenRect.YMost() + aTranslation->y;
|
||||
|
||||
nscoord minY;
|
||||
if (!PresContext()->IsChrome()) {
|
||||
nsIFrame* root = PresContext()->PresShell()->GetRootFrame();
|
||||
minY = root->GetScreenRectInAppUnits().y;
|
||||
if (dropdownY < root->GetScreenRectInAppUnits().y) {
|
||||
// Don't allow the drop-down to be placed above the top of the root frame.
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
minY = screen.y;
|
||||
}
|
||||
|
||||
nscoord below = screen.YMost() - dropdownY;
|
||||
nscoord above = thisScreenRect.y + aTranslation->y - minY;
|
||||
|
||||
// If the difference between the space above and below is less
|
||||
// than a row-height, then we favor the space below.
|
||||
if (above >= below) {
|
||||
nsListControlFrame* lcf = static_cast<nsListControlFrame*>(mDropdownFrame);
|
||||
nscoord rowHeight = lcf->GetHeightOfARow();
|
||||
if (above < below + rowHeight) {
|
||||
above -= rowHeight;
|
||||
}
|
||||
}
|
||||
|
||||
*aBelow = below;
|
||||
*aAbove = above;
|
||||
}
|
||||
|
||||
nsComboboxControlFrame::DropDownPositionState
|
||||
nsComboboxControlFrame::AbsolutelyPositionDropDown()
|
||||
{
|
||||
nsPoint translation;
|
||||
nscoord above, below;
|
||||
GetAvailableDropdownSpace(&above, &below, &translation);
|
||||
if (above <= 0 && below <= 0) {
|
||||
// Hide the view immediately to minimize flicker.
|
||||
nsIView* view = mDropdownFrame->GetView();
|
||||
view->GetViewManager()->SetViewVisibility(view, nsViewVisibility_kHide);
|
||||
NS_DispatchToCurrentThread(new nsAsyncRollup(this));
|
||||
return eDropDownPositionSuppressed;
|
||||
}
|
||||
nsPoint translation = GetCSSTransformTranslation();
|
||||
|
||||
// Use the height calculated for the area frame so it includes both
|
||||
// the display and button heights.
|
||||
nscoord dropdownYOffset = GetRect().height;
|
||||
nsSize dropdownSize = mDropdownFrame->GetSize();
|
||||
nscoord height = NS_MAX(above, below);
|
||||
nsListControlFrame* lcf = static_cast<nsListControlFrame*>(mDropdownFrame);
|
||||
if (height < dropdownSize.height) {
|
||||
if (lcf->GetNumDisplayRows() > 1) {
|
||||
// The drop-down doesn't fit and currently shows more than 1 row -
|
||||
// schedule a resize to show fewer rows.
|
||||
NS_DispatchToCurrentThread(new nsAsyncResize(this));
|
||||
return eDropDownPositionPendingResize;
|
||||
}
|
||||
} else if (height > (dropdownSize.height + lcf->GetHeightOfARow() * 1.5) &&
|
||||
lcf->GetDropdownCanGrow()) {
|
||||
// The drop-down fits but there is room for at least 1.5 more rows -
|
||||
// schedule a resize to show more rows if it has more rows to show.
|
||||
// (1.5 rows for good measure to avoid any rounding issues that would
|
||||
// lead to a loop of reflow requests)
|
||||
NS_DispatchToCurrentThread(new nsAsyncResize(this));
|
||||
return eDropDownPositionPendingResize;
|
||||
|
||||
nsRect screen = nsFormControlFrame::GetUsableScreenRect(PresContext());
|
||||
|
||||
// Check to see if the drop-down list will go offscreen
|
||||
if ((GetScreenRectInAppUnits() + translation).YMost() + dropdownSize.height > screen.YMost()) {
|
||||
// move the dropdown list up
|
||||
dropdownYOffset = - (dropdownSize.height);
|
||||
}
|
||||
|
||||
// Position the drop-down below if there is room, otherwise place it
|
||||
// on the side that has more room.
|
||||
bool b = dropdownSize.height <= below || below >= above;
|
||||
nsPoint dropdownPosition(0, b ? GetRect().height : -dropdownSize.height);
|
||||
if (GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
|
||||
nsPoint dropdownPosition;
|
||||
const nsStyleVisibility* vis = GetStyleVisibility();
|
||||
if (vis->mDirection == NS_STYLE_DIRECTION_RTL) {
|
||||
// Align the right edge of the drop-down with the right edge of the control.
|
||||
dropdownPosition.x = GetRect().width - dropdownSize.width;
|
||||
} else {
|
||||
dropdownPosition.x = 0;
|
||||
}
|
||||
mDropdownFrame->SetPosition(dropdownPosition + translation);
|
||||
nsContainerFrame::PositionFrameView(mDropdownFrame);
|
||||
return eDropDownPositionFinal;
|
||||
}
|
||||
dropdownPosition.y = dropdownYOffset;
|
||||
|
||||
void
|
||||
nsComboboxControlFrame::NotifyGeometryChange()
|
||||
{
|
||||
// We don't need to resize if we're not dropped down since ShowDropDown
|
||||
// does that, or if we're dirty then the reflow callback does it,
|
||||
// or if we have a delayed ShowDropDown pending.
|
||||
if (IsDroppedDown() &&
|
||||
!(GetStateBits() & NS_FRAME_IS_DIRTY) &&
|
||||
!mDelayedShowDropDown) {
|
||||
// Async because we're likely in a middle of a scroll here so
|
||||
// frame/view positions are in flux.
|
||||
nsRefPtr<nsResizeDropdownAtFinalPosition> resize =
|
||||
new nsResizeDropdownAtFinalPosition(this);
|
||||
NS_DispatchToCurrentThread(resize);
|
||||
}
|
||||
mDropdownFrame->SetPosition(dropdownPosition + translation);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
@ -867,13 +706,6 @@ nsComboboxControlFrame::Reflow(nsPresContext* aPresContext,
|
|||
|
||||
// First reflow our dropdown so that we know how tall we should be.
|
||||
ReflowDropdown(aPresContext, aReflowState);
|
||||
nsRefPtr<nsResizeDropdownAtFinalPosition> resize =
|
||||
new nsResizeDropdownAtFinalPosition(this);
|
||||
if (NS_SUCCEEDED(aPresContext->PresShell()->PostReflowCallback(resize))) {
|
||||
// The reflow callback queue doesn't AddRef so we keep it alive until
|
||||
// it's released in its ReflowFinished / ReflowCallbackCanceled.
|
||||
resize.forget();
|
||||
}
|
||||
|
||||
// Get the width of the vertical scrollbar. That will be the width of the
|
||||
// dropdown button.
|
||||
|
@ -962,25 +794,16 @@ nsComboboxControlFrame::GetFrameName(nsAString& aResult) const
|
|||
void
|
||||
nsComboboxControlFrame::ShowDropDown(bool aDoDropDown)
|
||||
{
|
||||
mDelayedShowDropDown = false;
|
||||
nsEventStates eventStates = mContent->AsElement()->State();
|
||||
if (aDoDropDown && eventStates.HasState(NS_EVENT_STATE_DISABLED)) {
|
||||
if (eventStates.HasState(NS_EVENT_STATE_DISABLED)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mDroppedDown && aDoDropDown) {
|
||||
if (sFocused == this) {
|
||||
DropDownPositionState state = AbsolutelyPositionDropDown();
|
||||
if (state == eDropDownPositionFinal) {
|
||||
ShowList(aDoDropDown); // might destroy us
|
||||
} else if (state == eDropDownPositionPendingResize) {
|
||||
// Delay until after the resize reflow, see nsAsyncResize.
|
||||
mDelayedShowDropDown = true;
|
||||
}
|
||||
} else {
|
||||
// Delay until we get focus, see SetFocus().
|
||||
mDelayedShowDropDown = true;
|
||||
if (mListControlFrame) {
|
||||
mListControlFrame->SyncViewWithFrame();
|
||||
}
|
||||
ShowList(aDoDropDown); // might destroy us
|
||||
} else if (mDroppedDown && !aDoDropDown) {
|
||||
ShowList(aDoDropDown); // might destroy us
|
||||
}
|
||||
|
@ -1613,7 +1436,7 @@ void nsComboboxControlFrame::PaintFocus(nsRenderingContext& aRenderingContext,
|
|||
{
|
||||
/* Do we need to do anything? */
|
||||
nsEventStates eventStates = mContent->AsElement()->State();
|
||||
if (eventStates.HasState(NS_EVENT_STATE_DISABLED) || sFocused != this)
|
||||
if (eventStates.HasState(NS_EVENT_STATE_DISABLED) || mFocused != this)
|
||||
return;
|
||||
|
||||
aRenderingContext.PushState();
|
||||
|
|
|
@ -137,16 +137,7 @@ public:
|
|||
* @note This method might destroy |this|.
|
||||
*/
|
||||
virtual void RollupFromList();
|
||||
|
||||
/**
|
||||
* Return the available space above and below this frame for
|
||||
* placing the drop-down list, and the current 2D translation.
|
||||
* Note that either or both can be less than or equal to zero,
|
||||
* if both are then the drop-down should be closed.
|
||||
*/
|
||||
void GetAvailableDropdownSpace(nscoord* aAbove,
|
||||
nscoord* aBelow,
|
||||
nsPoint* aTranslation);
|
||||
virtual void AbsolutelyPositionDropDown();
|
||||
virtual PRInt32 GetIndexOfDisplayArea();
|
||||
/**
|
||||
* @note This method might destroy |this|.
|
||||
|
@ -168,7 +159,6 @@ public:
|
|||
* @note This method might destroy |this|.
|
||||
*/
|
||||
virtual nsIContent* Rollup(PRUint32 aCount, bool aGetLastRolledUp = false);
|
||||
virtual void NotifyGeometryChange();
|
||||
|
||||
/**
|
||||
* A combobox should roll up if a mousewheel event happens outside of
|
||||
|
@ -194,27 +184,17 @@ public:
|
|||
static bool ToolkitHasNativePopup();
|
||||
|
||||
protected:
|
||||
friend class RedisplayTextEvent;
|
||||
friend class nsAsyncResize;
|
||||
friend class nsResizeDropdownAtFinalPosition;
|
||||
|
||||
// Utilities
|
||||
nsresult ReflowDropdown(nsPresContext* aPresContext,
|
||||
const nsHTMLReflowState& aReflowState);
|
||||
|
||||
enum DropDownPositionState {
|
||||
// can't show the dropdown at its current position
|
||||
eDropDownPositionSuppressed,
|
||||
// a resize reflow is pending, don't show it yet
|
||||
eDropDownPositionPendingResize,
|
||||
// the dropdown has its final size and position and can be displayed here
|
||||
eDropDownPositionFinal
|
||||
};
|
||||
DropDownPositionState AbsolutelyPositionDropDown();
|
||||
|
||||
// Helper for GetMinWidth/GetPrefWidth
|
||||
nscoord GetIntrinsicWidth(nsRenderingContext* aRenderingContext,
|
||||
nsLayoutUtils::IntrinsicWidthType aType);
|
||||
protected:
|
||||
class RedisplayTextEvent;
|
||||
friend class RedisplayTextEvent;
|
||||
|
||||
class RedisplayTextEvent : public nsRunnable {
|
||||
public:
|
||||
|
@ -262,6 +242,9 @@ protected:
|
|||
// size to the full width except the drop-marker.
|
||||
nscoord mDisplayWidth;
|
||||
|
||||
bool mDroppedDown; // Current state of the dropdown list, true is dropped down
|
||||
bool mInRedisplayText;
|
||||
|
||||
nsRevocableEventPtr<RedisplayTextEvent> mRedisplayTextEvent;
|
||||
|
||||
PRInt32 mRecentSelectedIndex;
|
||||
|
@ -272,16 +255,9 @@ protected:
|
|||
// then open or close the combo box.
|
||||
nsCOMPtr<nsIDOMEventListener> mButtonListener;
|
||||
|
||||
// Current state of the dropdown list, true is dropped down.
|
||||
bool mDroppedDown;
|
||||
// See comment in HandleRedisplayTextEvent().
|
||||
bool mInRedisplayText;
|
||||
// Acting on ShowDropDown(true) is delayed until we're focused.
|
||||
bool mDelayedShowDropDown;
|
||||
|
||||
// static class data member for Bug 32920
|
||||
// only one control can be focused at a time
|
||||
static nsComboboxControlFrame* sFocused;
|
||||
static nsComboboxControlFrame * mFocused;
|
||||
|
||||
#ifdef DO_REFLOW_COUNTER
|
||||
PRInt32 mReflowId;
|
||||
|
|
|
@ -60,6 +60,11 @@ public:
|
|||
*/
|
||||
virtual PRInt32 UpdateRecentIndex(PRInt32 aIndex) = 0;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
virtual void AbsolutelyPositionDropDown() = 0;
|
||||
|
||||
/**
|
||||
* Notification that the content has been reset
|
||||
*/
|
||||
|
|
|
@ -61,6 +61,11 @@ public:
|
|||
|
||||
virtual PRInt32 GetNumberOfOptions() = 0;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
virtual void SyncViewWithFrame() = 0;
|
||||
|
||||
/**
|
||||
* Called by combobox when it's about to drop down
|
||||
*/
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
using namespace mozilla;
|
||||
|
||||
// Constants
|
||||
const PRInt32 kMaxDropDownRows = 20; // This matches the setting for 4.x browsers
|
||||
const nscoord kMaxDropDownRows = 20; // This matches the setting for 4.x browsers
|
||||
const PRInt32 kNothingSelected = -1;
|
||||
|
||||
// Static members
|
||||
|
@ -112,7 +112,6 @@ nsListControlFrame::nsListControlFrame(
|
|||
: nsHTMLScrollFrame(aShell, aContext, false),
|
||||
mMightNeedSecondPass(false),
|
||||
mHasPendingInterruptAtStartOfReflow(false),
|
||||
mDropdownCanGrow(false),
|
||||
mLastDropdownComputedHeight(NS_UNCONSTRAINEDSIZE)
|
||||
{
|
||||
mComboboxFrame = nsnull;
|
||||
|
@ -510,12 +509,11 @@ nsListControlFrame::ReflowAsDropdown(nsPresContext* aPresContext,
|
|||
|
||||
#ifdef DEBUG
|
||||
nscoord oldHeightOfARow = HeightOfARow();
|
||||
nscoord oldVisibleHeight = (GetStateBits() & NS_FRAME_FIRST_REFLOW) ?
|
||||
NS_UNCONSTRAINEDSIZE : GetScrolledFrame()->GetSize().height;
|
||||
#endif
|
||||
|
||||
nsHTMLReflowState state(aReflowState);
|
||||
|
||||
nscoord oldVisibleHeight;
|
||||
if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
|
||||
// When not doing an initial reflow, and when the height is auto, start off
|
||||
// with our computed height set to what we'd expect our height to be.
|
||||
|
@ -523,6 +521,11 @@ nsListControlFrame::ReflowAsDropdown(nsPresContext* aPresContext,
|
|||
// NS_UNCONSTRAINEDSIZE in cases when last time we didn't have to constrain
|
||||
// the height. That's fine; just do the same thing as last time.
|
||||
state.SetComputedHeight(mLastDropdownComputedHeight);
|
||||
oldVisibleHeight = GetScrolledFrame()->GetSize().height;
|
||||
} else {
|
||||
// Set oldVisibleHeight to something that will never test true against a
|
||||
// real height.
|
||||
oldVisibleHeight = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
|
||||
nsresult rv = nsHTMLScrollFrame::Reflow(aPresContext, aDesiredSize,
|
||||
|
@ -564,34 +567,48 @@ nsListControlFrame::ReflowAsDropdown(nsPresContext* aPresContext,
|
|||
// implementation detail of nsHTMLScrollFrame that we're depending on?
|
||||
nsHTMLScrollFrame::DidReflow(aPresContext, &state, aStatus);
|
||||
|
||||
// Now compute the height we want to have.
|
||||
// Note: no need to apply min/max constraints, since we have no such
|
||||
// rules applied to the combobox dropdown.
|
||||
// Now compute the height we want to have
|
||||
mNumDisplayRows = kMaxDropDownRows;
|
||||
if (visibleHeight > mNumDisplayRows * heightOfARow) {
|
||||
visibleHeight = mNumDisplayRows * heightOfARow;
|
||||
// This is an adaptive algorithm for figuring out how many rows
|
||||
// should be displayed in the drop down. The standard size is 20 rows,
|
||||
// but on 640x480 it is typically too big.
|
||||
// This takes the height of the screen divides it by two and then subtracts off
|
||||
// an estimated height of the combobox. I estimate it by taking the max element size
|
||||
// of the drop down and multiplying it by 2 (this is arbitrary) then subtract off
|
||||
// the border and padding of the drop down (again rather arbitrary)
|
||||
// This all breaks down if the font of the combobox is a lot larger then the option items
|
||||
// or CSS style has set the height of the combobox to be rather large.
|
||||
// We can fix these cases later if they actually happen.
|
||||
nsRect screen = nsFormControlFrame::GetUsableScreenRect(aPresContext);
|
||||
nscoord screenHeight = screen.height;
|
||||
|
||||
mDropdownCanGrow = false;
|
||||
if (visibleHeight <= 0 || heightOfARow <= 0) {
|
||||
nscoord availDropHgt = (screenHeight / 2) - (heightOfARow*2); // approx half screen minus combo size
|
||||
availDropHgt -= aReflowState.mComputedBorderPadding.top + aReflowState.mComputedBorderPadding.bottom;
|
||||
|
||||
nscoord hgt = visibleHeight + aReflowState.mComputedBorderPadding.top + aReflowState.mComputedBorderPadding.bottom;
|
||||
if (heightOfARow > 0) {
|
||||
if (hgt > availDropHgt) {
|
||||
visibleHeight = (availDropHgt / heightOfARow) * heightOfARow;
|
||||
}
|
||||
mNumDisplayRows = visibleHeight / heightOfARow;
|
||||
} else {
|
||||
// Hmmm, not sure what to do here. Punt, and make both of them one
|
||||
visibleHeight = 1;
|
||||
mNumDisplayRows = 1;
|
||||
}
|
||||
|
||||
state.SetComputedHeight(mNumDisplayRows * heightOfARow);
|
||||
// Note: no need to apply min/max constraints, since we have no such
|
||||
// rules applied to the combobox dropdown.
|
||||
// XXXbz this is ending up too big!! Figure out why.
|
||||
} else if (visibleHeight == 0) {
|
||||
// Looks like we have no options. Just size us to a single row height.
|
||||
state.SetComputedHeight(heightOfARow);
|
||||
mNumDisplayRows = 1;
|
||||
} else {
|
||||
nsComboboxControlFrame* combobox = static_cast<nsComboboxControlFrame*>(mComboboxFrame);
|
||||
nsPoint translation;
|
||||
nscoord above, below;
|
||||
combobox->GetAvailableDropdownSpace(&above, &below, &translation);
|
||||
if (above <= 0 && below <= 0) {
|
||||
state.SetComputedHeight(heightOfARow);
|
||||
mNumDisplayRows = 1;
|
||||
} else {
|
||||
nscoord bp = aReflowState.mComputedBorderPadding.TopBottom();
|
||||
nscoord availableHeight = NS_MAX(above, below) - bp;
|
||||
nscoord height = NS_MIN(visibleHeight, availableHeight);
|
||||
PRInt32 rows = height / heightOfARow;
|
||||
mNumDisplayRows = clamped(rows, 1, kMaxDropDownRows);
|
||||
nscoord newHeight = mNumDisplayRows * heightOfARow;
|
||||
state.SetComputedHeight(newHeight);
|
||||
mDropdownCanGrow = visibleHeight - newHeight >= heightOfARow &&
|
||||
mNumDisplayRows != kMaxDropDownRows;
|
||||
}
|
||||
// Not too big, not too small. Just use it!
|
||||
state.SetComputedHeight(NS_UNCONSTRAINEDSIZE);
|
||||
}
|
||||
|
||||
// Note: At this point, state.mComputedHeight can be NS_UNCONSTRAINEDSIZE in
|
||||
|
@ -1580,6 +1597,18 @@ nsListControlFrame::GetFormProperty(nsIAtom* aName, nsAString& aValue) const
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsListControlFrame::SyncViewWithFrame()
|
||||
{
|
||||
// Resync the view's position with the frame.
|
||||
// The problem is the dropdown's view is attached directly under
|
||||
// the root view. This means its view needs to have its coordinates calculated
|
||||
// as if it were in it's normal position in the view hierarchy.
|
||||
mComboboxFrame->AbsolutelyPositionDropDown();
|
||||
|
||||
nsContainerFrame::PositionFrameView(this);
|
||||
}
|
||||
|
||||
void
|
||||
nsListControlFrame::AboutToDropDown()
|
||||
{
|
||||
|
@ -1644,7 +1673,14 @@ nsListControlFrame::DidReflow(nsPresContext* aPresContext,
|
|||
bool wasInterrupted = !mHasPendingInterruptAtStartOfReflow &&
|
||||
aPresContext->HasPendingInterrupt();
|
||||
|
||||
rv = nsHTMLScrollFrame::DidReflow(aPresContext, aReflowState, aStatus);
|
||||
if (IsInDropDownMode())
|
||||
{
|
||||
//SyncViewWithFrame();
|
||||
rv = nsHTMLScrollFrame::DidReflow(aPresContext, aReflowState, aStatus);
|
||||
SyncViewWithFrame();
|
||||
} else {
|
||||
rv = nsHTMLScrollFrame::DidReflow(aPresContext, aReflowState, aStatus);
|
||||
}
|
||||
|
||||
if (mNeedToReset && !wasInterrupted) {
|
||||
mNeedToReset = false;
|
||||
|
|
|
@ -130,6 +130,7 @@ public:
|
|||
virtual void CaptureMouseEvents(bool aGrabMouseEvents);
|
||||
virtual nscoord GetHeightOfARow();
|
||||
virtual PRInt32 GetNumberOfOptions();
|
||||
virtual void SyncViewWithFrame();
|
||||
virtual void AboutToDropDown();
|
||||
|
||||
/**
|
||||
|
@ -231,17 +232,6 @@ public:
|
|||
*/
|
||||
bool IsInDropDownMode() const;
|
||||
|
||||
/**
|
||||
* Return the number of displayed rows in the list.
|
||||
*/
|
||||
PRUint32 GetNumDisplayRows() const { return mNumDisplayRows; }
|
||||
|
||||
/**
|
||||
* Return true if the drop-down list can display more rows.
|
||||
* (always false if not in drop-down mode)
|
||||
*/
|
||||
bool GetDropdownCanGrow() const { return mDropdownCanGrow; }
|
||||
|
||||
/**
|
||||
* Dropdowns need views
|
||||
*/
|
||||
|
@ -424,10 +414,6 @@ protected:
|
|||
*/
|
||||
bool mHasPendingInterruptAtStartOfReflow:1;
|
||||
|
||||
// True if the drop-down can show more rows. Always false if this list
|
||||
// is not in drop-down mode.
|
||||
bool mDropdownCanGrow:1;
|
||||
|
||||
// The last computed height we reflowed at if we're a combobox dropdown.
|
||||
// XXXbz should we be using a subclass here? Or just not worry
|
||||
// about the extra member on listboxes?
|
||||
|
|
|
@ -289,7 +289,6 @@ public:
|
|||
virtual bool ShouldRollupOnMouseWheelEvent();
|
||||
virtual bool ShouldRollupOnMouseActivate();
|
||||
virtual PRUint32 GetSubmenuWidgetChain(nsTArray<nsIWidget*> *aWidgetChain);
|
||||
virtual void NotifyGeometryChange() {}
|
||||
|
||||
static nsXULPopupManager* sInstance;
|
||||
|
||||
|
|
|
@ -835,7 +835,6 @@ NS_IMETHODIMP nsChildView::Move(PRInt32 aX, PRInt32 aY)
|
|||
if (mVisible)
|
||||
[mView setNeedsDisplay:YES];
|
||||
|
||||
NotifyRollupGeometryChange(gRollupListener);
|
||||
ReportMoveEvent();
|
||||
|
||||
return NS_OK;
|
||||
|
@ -860,7 +859,6 @@ NS_IMETHODIMP nsChildView::Resize(PRInt32 aWidth, PRInt32 aHeight, bool aRepaint
|
|||
if (mVisible && aRepaint)
|
||||
[mView setNeedsDisplay:YES];
|
||||
|
||||
NotifyRollupGeometryChange(gRollupListener);
|
||||
ReportSizeEvent();
|
||||
|
||||
return NS_OK;
|
||||
|
@ -893,7 +891,6 @@ NS_IMETHODIMP nsChildView::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt3
|
|||
if (mVisible && aRepaint)
|
||||
[mView setNeedsDisplay:YES];
|
||||
|
||||
NotifyRollupGeometryChange(gRollupListener);
|
||||
if (isMoving) {
|
||||
ReportMoveEvent();
|
||||
if (mOnDestroyCalled)
|
||||
|
|
|
@ -1064,8 +1064,6 @@ nsWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, bool aRepaint)
|
|||
}
|
||||
}
|
||||
|
||||
NotifyRollupGeometryChange(gRollupListener);
|
||||
|
||||
// synthesize a resize event if this isn't a toplevel
|
||||
if (mIsTopLevel || mListenForResizes) {
|
||||
nsIntRect rect(mBounds.x, mBounds.y, aWidth, aHeight);
|
||||
|
@ -1130,8 +1128,6 @@ nsWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight,
|
|||
}
|
||||
}
|
||||
|
||||
NotifyRollupGeometryChange(gRollupListener);
|
||||
|
||||
if (mIsTopLevel || mListenForResizes) {
|
||||
// synthesize a resize event
|
||||
nsIntRect rect(aX, aY, aWidth, aHeight);
|
||||
|
@ -1195,7 +1191,6 @@ nsWindow::Move(PRInt32 aX, PRInt32 aY)
|
|||
gdk_window_move(mGdkWindow, aX, aY);
|
||||
}
|
||||
|
||||
NotifyRollupGeometryChange(gRollupListener);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,11 +45,6 @@ class nsIRollupListener {
|
|||
* the same number of widgets added to aWidgetChain.
|
||||
*/
|
||||
virtual PRUint32 GetSubmenuWidgetChain(nsTArray<nsIWidget*> *aWidgetChain) = 0;
|
||||
|
||||
/**
|
||||
* Notify the RollupListener that the widget did a Move or Resize.
|
||||
*/
|
||||
virtual void NotifyGeometryChange() = 0;
|
||||
};
|
||||
|
||||
#endif /* __nsIRollupListener_h__ */
|
||||
|
|
|
@ -766,9 +766,7 @@ void nsWindow::NS2PM_PARENT(POINTL& ptl)
|
|||
NS_METHOD nsWindow::Move(PRInt32 aX, PRInt32 aY)
|
||||
{
|
||||
if (mFrame) {
|
||||
nsresult rv = mFrame->Move(aX, aY);
|
||||
NotifyRollupGeometryChange(gRollupListener);
|
||||
return rv;
|
||||
return mFrame->Move(aX, aY);
|
||||
}
|
||||
Resize(aX, aY, mBounds.width, mBounds.height, false);
|
||||
return NS_OK;
|
||||
|
@ -779,9 +777,7 @@ NS_METHOD nsWindow::Move(PRInt32 aX, PRInt32 aY)
|
|||
NS_METHOD nsWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, bool aRepaint)
|
||||
{
|
||||
if (mFrame) {
|
||||
nsresult rv = mFrame->Resize(aWidth, aHeight, aRepaint);
|
||||
NotifyRollupGeometryChange(gRollupListener);
|
||||
return rv;
|
||||
return mFrame->Resize(aWidth, aHeight, aRepaint);
|
||||
}
|
||||
Resize(mBounds.x, mBounds.y, aWidth, aHeight, aRepaint);
|
||||
return NS_OK;
|
||||
|
@ -793,9 +789,7 @@ NS_METHOD nsWindow::Resize(PRInt32 aX, PRInt32 aY,
|
|||
PRInt32 aWidth, PRInt32 aHeight, bool aRepaint)
|
||||
{
|
||||
if (mFrame) {
|
||||
nsresult rv = mFrame->Resize(aX, aY, aWidth, aHeight, aRepaint);
|
||||
NotifyRollupGeometryChange(gRollupListener);
|
||||
return rv;
|
||||
return mFrame->Resize(aX, aY, aWidth, aHeight, aRepaint);
|
||||
}
|
||||
|
||||
// For mWnd & eWindowType_child set the cached values upfront, see bug 286555.
|
||||
|
@ -833,7 +827,6 @@ NS_METHOD nsWindow::Resize(PRInt32 aX, PRInt32 aY,
|
|||
}
|
||||
}
|
||||
|
||||
NotifyRollupGeometryChange(gRollupListener);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -546,7 +546,7 @@ nsWindow::Move(PRInt32 aX, PRInt32 aY)
|
|||
mBounds.x = pos.x();
|
||||
mBounds.y = pos.y();
|
||||
|
||||
NotifyRollupGeometryChange(gRollupListener);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -3011,7 +3011,6 @@ nsWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, bool aRepaint)
|
|||
DispatchResizeEvent(rect, status);
|
||||
}
|
||||
|
||||
NotifyRollupGeometryChange(gRollupListener);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -3075,7 +3074,6 @@ nsWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight,
|
|||
if (aRepaint)
|
||||
mWidget->update();
|
||||
|
||||
NotifyRollupGeometryChange(gRollupListener);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -1328,7 +1328,6 @@ NS_METHOD nsWindow::Move(PRInt32 aX, PRInt32 aY)
|
|||
|
||||
SetThemeRegion();
|
||||
}
|
||||
NotifyRollupGeometryChange(sRollupListener);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1366,7 +1365,6 @@ NS_METHOD nsWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, bool aRepaint)
|
|||
if (aRepaint)
|
||||
Invalidate();
|
||||
|
||||
NotifyRollupGeometryChange(sRollupListener);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1406,7 +1404,6 @@ NS_METHOD nsWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeig
|
|||
if (aRepaint)
|
||||
Invalidate();
|
||||
|
||||
NotifyRollupGeometryChange(sRollupListener);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include "nsGUIEvent.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "BasicLayers.h"
|
||||
#include "nsIRollupListener.h"
|
||||
|
||||
class nsIContent;
|
||||
class nsAutoRollup;
|
||||
|
@ -266,13 +265,6 @@ protected:
|
|||
|
||||
BasicLayerManager* CreateBasicLayerManager();
|
||||
|
||||
void NotifyRollupGeometryChange(nsIRollupListener* aRollupListener)
|
||||
{
|
||||
if (aRollupListener) {
|
||||
aRollupListener->NotifyGeometryChange();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Starts the OMTC compositor destruction sequence.
|
||||
|
|
Загрузка…
Ссылка в новой задаче