2002-01-12 04:18:10 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2012-05-21 15:12:37 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
#include "nsListBoxBodyFrame.h"
|
|
|
|
|
|
|
|
#include "nsListBoxLayout.h"
|
|
|
|
|
2014-10-09 16:14:26 +04:00
|
|
|
#include "mozilla/MathAlgorithms.h"
|
2002-01-12 04:18:10 +03:00
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "nsGridRowGroupLayout.h"
|
|
|
|
#include "nsIServiceManager.h"
|
2006-12-26 20:47:52 +03:00
|
|
|
#include "nsGkAtoms.h"
|
2002-01-12 04:18:10 +03:00
|
|
|
#include "nsIContent.h"
|
2014-02-28 03:04:46 +04:00
|
|
|
#include "nsNameSpaceManager.h"
|
2002-01-12 04:18:10 +03:00
|
|
|
#include "nsIDocument.h"
|
|
|
|
#include "nsIDOMMouseEvent.h"
|
|
|
|
#include "nsIDOMElement.h"
|
|
|
|
#include "nsIDOMNodeList.h"
|
|
|
|
#include "nsCSSFrameConstructor.h"
|
|
|
|
#include "nsIScrollableFrame.h"
|
2011-07-11 18:05:09 +04:00
|
|
|
#include "nsScrollbarFrame.h"
|
2013-01-03 17:23:11 +04:00
|
|
|
#include "nsView.h"
|
2013-01-05 07:12:24 +04:00
|
|
|
#include "nsViewManager.h"
|
2003-02-22 03:32:13 +03:00
|
|
|
#include "nsStyleContext.h"
|
2011-04-08 05:05:49 +04:00
|
|
|
#include "nsFontMetrics.h"
|
2002-01-12 04:18:10 +03:00
|
|
|
#include "nsITimer.h"
|
2016-02-24 10:01:11 +03:00
|
|
|
#include "mozilla/StyleSetHandle.h"
|
|
|
|
#include "mozilla/StyleSetHandleInlines.h"
|
2004-04-28 05:14:50 +04:00
|
|
|
#include "nsPIBoxObject.h"
|
2004-11-03 05:52:16 +03:00
|
|
|
#include "nsLayoutUtils.h"
|
2006-01-31 00:29:10 +03:00
|
|
|
#include "nsPIListBoxObject.h"
|
2006-04-24 09:40:11 +04:00
|
|
|
#include "nsContentUtils.h"
|
2013-05-02 02:50:08 +04:00
|
|
|
#include "ChildIterator.h"
|
2011-08-14 21:08:04 +04:00
|
|
|
#include "nsRenderingContext.h"
|
2013-07-03 19:56:26 +04:00
|
|
|
#include "prtime.h"
|
2013-01-15 16:22:03 +04:00
|
|
|
#include <algorithm>
|
2002-01-12 04:18:10 +03:00
|
|
|
|
2012-03-27 11:29:51 +04:00
|
|
|
#ifdef ACCESSIBILITY
|
|
|
|
#include "nsAccessibilityService.h"
|
|
|
|
#endif
|
|
|
|
|
2014-10-09 16:14:26 +04:00
|
|
|
using namespace mozilla;
|
2013-05-02 02:50:08 +04:00
|
|
|
using namespace mozilla::dom;
|
|
|
|
|
2002-01-12 04:18:10 +03:00
|
|
|
/////////////// nsListScrollSmoother //////////////////
|
|
|
|
|
|
|
|
/* A mediator used to smooth out scrolling. It works by seeing if
|
|
|
|
* we have time to scroll the amount of rows requested. This is determined
|
|
|
|
* by measuring how long it takes to scroll a row. If we can scroll the
|
|
|
|
* rows in time we do so. If not we start a timer and skip the request. We
|
|
|
|
* do this until the timer finally first because the user has stopped moving
|
|
|
|
* the mouse. Then do all the queued requests in on shot.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// the longest amount of time that can go by before the use
|
|
|
|
// notices it as a delay.
|
|
|
|
#define USER_TIME_THRESHOLD 150000
|
|
|
|
|
2005-11-21 01:05:24 +03:00
|
|
|
// how long it takes to layout a single row initial value.
|
2002-01-12 04:18:10 +03:00
|
|
|
// we will time this after we scroll a few rows.
|
|
|
|
#define TIME_PER_ROW_INITAL 50000
|
|
|
|
|
|
|
|
// if we decide we can't layout the rows in the amount of time. How long
|
|
|
|
// do we wait before checking again?
|
|
|
|
#define SMOOTH_INTERVAL 100
|
|
|
|
|
2015-03-21 19:28:04 +03:00
|
|
|
class nsListScrollSmoother final : public nsITimerCallback
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
2014-06-24 02:40:01 +04:00
|
|
|
private:
|
|
|
|
virtual ~nsListScrollSmoother();
|
|
|
|
|
2002-01-12 04:18:10 +03:00
|
|
|
public:
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
|
2014-09-01 07:36:37 +04:00
|
|
|
explicit nsListScrollSmoother(nsListBoxBodyFrame* aOuter);
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
// nsITimerCallback
|
2002-09-07 09:38:16 +04:00
|
|
|
NS_DECL_NSITIMERCALLBACK
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
void Start();
|
|
|
|
void Stop();
|
2011-09-29 10:19:26 +04:00
|
|
|
bool IsRunning();
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
nsCOMPtr<nsITimer> mRepeatTimer;
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t mDelta;
|
2002-01-12 04:18:10 +03:00
|
|
|
nsListBoxBodyFrame* mOuter;
|
|
|
|
};
|
|
|
|
|
|
|
|
nsListScrollSmoother::nsListScrollSmoother(nsListBoxBodyFrame* aOuter)
|
|
|
|
{
|
|
|
|
mDelta = 0;
|
|
|
|
mOuter = aOuter;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsListScrollSmoother::~nsListScrollSmoother()
|
|
|
|
{
|
|
|
|
Stop();
|
|
|
|
}
|
|
|
|
|
2002-09-07 09:38:16 +04:00
|
|
|
NS_IMETHODIMP
|
2002-01-12 04:18:10 +03:00
|
|
|
nsListScrollSmoother::Notify(nsITimer *timer)
|
|
|
|
{
|
|
|
|
Stop();
|
|
|
|
|
|
|
|
NS_ASSERTION(mOuter, "mOuter is null, see bug #68365");
|
2002-09-07 09:38:16 +04:00
|
|
|
if (!mOuter) return NS_OK;
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
// actually do some work.
|
|
|
|
mOuter->InternalPositionChangedCallback();
|
2002-09-07 09:38:16 +04:00
|
|
|
return NS_OK;
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2002-01-12 04:18:10 +03:00
|
|
|
nsListScrollSmoother::IsRunning()
|
|
|
|
{
|
2011-10-17 18:59:28 +04:00
|
|
|
return mRepeatTimer ? true : false;
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsListScrollSmoother::Start()
|
|
|
|
{
|
|
|
|
Stop();
|
|
|
|
mRepeatTimer = do_CreateInstance("@mozilla.org/timer;1");
|
2002-09-07 09:38:16 +04:00
|
|
|
mRepeatTimer->InitWithCallback(this, SMOOTH_INTERVAL, nsITimer::TYPE_ONE_SHOT);
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsListScrollSmoother::Stop()
|
|
|
|
{
|
|
|
|
if ( mRepeatTimer ) {
|
|
|
|
mRepeatTimer->Cancel();
|
2012-07-30 18:20:58 +04:00
|
|
|
mRepeatTimer = nullptr;
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-27 11:06:00 +04:00
|
|
|
NS_IMPL_ISUPPORTS(nsListScrollSmoother, nsITimerCallback)
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
/////////////// nsListBoxBodyFrame //////////////////
|
|
|
|
|
2015-01-06 12:27:56 +03:00
|
|
|
nsListBoxBodyFrame::nsListBoxBodyFrame(nsStyleContext* aContext,
|
2011-07-11 18:05:10 +04:00
|
|
|
nsBoxLayout* aLayoutManager)
|
2015-01-06 12:27:56 +03:00
|
|
|
: nsBoxFrame(aContext, false, aLayoutManager),
|
2012-07-30 18:20:58 +04:00
|
|
|
mTopFrame(nullptr),
|
|
|
|
mBottomFrame(nullptr),
|
|
|
|
mLinkupFrame(nullptr),
|
|
|
|
mScrollSmoother(nullptr),
|
2002-01-12 04:18:10 +03:00
|
|
|
mRowsToPrepend(0),
|
2009-05-12 14:13:09 +04:00
|
|
|
mRowCount(-1),
|
|
|
|
mRowHeight(0),
|
|
|
|
mAvailableHeight(0),
|
|
|
|
mStringWidth(-1),
|
2002-01-12 04:18:10 +03:00
|
|
|
mCurrentIndex(0),
|
|
|
|
mOldIndex(0),
|
|
|
|
mYPosition(0),
|
|
|
|
mTimePerRow(TIME_PER_ROW_INITAL),
|
2011-10-17 18:59:28 +04:00
|
|
|
mRowHeightWasSet(false),
|
|
|
|
mScrolling(false),
|
|
|
|
mAdjustScroll(false),
|
|
|
|
mReflowCallbackPosted(false)
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
nsListBoxBodyFrame::~nsListBoxBodyFrame()
|
|
|
|
{
|
|
|
|
NS_IF_RELEASE(mScrollSmoother);
|
|
|
|
|
|
|
|
#if USE_TIMER_TO_DELAY_SCROLLING
|
|
|
|
StopScrollTracking();
|
2012-07-30 18:20:58 +04:00
|
|
|
mAutoScrollTimer = nullptr;
|
2002-01-12 04:18:10 +03:00
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2009-01-12 22:20:59 +03:00
|
|
|
NS_QUERYFRAME_HEAD(nsListBoxBodyFrame)
|
|
|
|
NS_QUERYFRAME_ENTRY(nsIScrollbarMediator)
|
|
|
|
NS_QUERYFRAME_ENTRY(nsListBoxBodyFrame)
|
|
|
|
NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame)
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
////////// nsIFrame /////////////////
|
|
|
|
|
2013-03-20 05:47:48 +04:00
|
|
|
void
|
2014-05-25 02:20:40 +04:00
|
|
|
nsListBoxBodyFrame::Init(nsIContent* aContent,
|
|
|
|
nsContainerFrame* aParent,
|
|
|
|
nsIFrame* aPrevInFlow)
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
2013-03-20 05:47:48 +04:00
|
|
|
nsBoxFrame::Init(aContent, aParent, aPrevInFlow);
|
2014-07-21 17:55:26 +04:00
|
|
|
// Don't call nsLayoutUtils::GetScrollableFrameFor since we are not its
|
|
|
|
// scrollframe child yet.
|
|
|
|
nsIScrollableFrame* scrollFrame = do_QueryFrame(aParent);
|
2007-06-21 13:35:41 +04:00
|
|
|
if (scrollFrame) {
|
2012-08-06 07:00:57 +04:00
|
|
|
nsIFrame* verticalScrollbar = scrollFrame->GetScrollbarBox(true);
|
2011-07-11 18:05:09 +04:00
|
|
|
nsScrollbarFrame* scrollbarFrame = do_QueryFrame(verticalScrollbar);
|
|
|
|
if (scrollbarFrame) {
|
2007-06-21 13:35:41 +04:00
|
|
|
scrollbarFrame->SetScrollbarMediatorContent(GetContent());
|
|
|
|
}
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
2016-03-17 08:55:48 +03:00
|
|
|
RefPtr<nsFontMetrics> fm =
|
|
|
|
nsLayoutUtils::GetFontMetricsForFrame(this, 1.0f);
|
2011-04-08 08:18:43 +04:00
|
|
|
mRowHeight = fm->MaxHeight();
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
2006-04-10 04:16:29 +04:00
|
|
|
void
|
2009-12-24 08:21:15 +03:00
|
|
|
nsListBoxBodyFrame::DestroyFrom(nsIFrame* aDestructRoot)
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
|
|
|
// make sure we cancel any posted callbacks.
|
2003-12-21 08:36:36 +03:00
|
|
|
if (mReflowCallbackPosted)
|
2007-03-31 01:11:41 +04:00
|
|
|
PresContext()->PresShell()->CancelReflowCallback(this);
|
2002-01-12 04:18:10 +03:00
|
|
|
|
2007-08-22 06:57:06 +04:00
|
|
|
// Revoke any pending position changed events
|
2012-08-22 19:56:38 +04:00
|
|
|
for (uint32_t i = 0; i < mPendingPositionChangeEvents.Length(); ++i) {
|
2007-08-22 06:57:06 +04:00
|
|
|
mPendingPositionChangeEvents[i]->Revoke();
|
|
|
|
}
|
|
|
|
|
2004-04-28 05:14:50 +04:00
|
|
|
// Make sure we tell our listbox's box object we're being destroyed.
|
2008-08-24 19:14:09 +04:00
|
|
|
if (mBoxObject) {
|
|
|
|
mBoxObject->ClearCachedValues();
|
2004-04-28 05:14:50 +04:00
|
|
|
}
|
|
|
|
|
2009-12-24 08:21:15 +03:00
|
|
|
nsBoxFrame::DestroyFrom(aDestructRoot);
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
2014-02-18 11:47:48 +04:00
|
|
|
nsresult
|
2012-08-22 19:56:38 +04:00
|
|
|
nsListBoxBodyFrame::AttributeChanged(int32_t aNameSpaceID,
|
2003-07-12 01:16:12 +04:00
|
|
|
nsIAtom* aAttribute,
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t aModType)
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
2004-04-28 05:14:50 +04:00
|
|
|
|
2006-12-26 20:47:52 +03:00
|
|
|
if (aAttribute == nsGkAtoms::rows) {
|
2010-05-13 17:44:14 +04:00
|
|
|
PresContext()->PresShell()->
|
|
|
|
FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
else
|
2005-09-07 20:49:21 +04:00
|
|
|
rv = nsBoxFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
return rv;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
Bug 300030: Move intrinsic width computation out of nsIFrame::Reflow and into its own methods on nsIFrame. Replace reflow reasons, types, and commands with dirty bits/notifications. Thanks to bzbarsky for almost all of the HTML form controls (mozilla/layout/forms) changes, and many others for help testing and patching. For detailed commit logs, see REFLOW_YYYYMMDD_BRANCH, where YYYYMMDD is one of 20061031, 20060830, 20060603, 20060302, 20060119, 20051011, 20050804, 20050429, 20050315, 20050111, and 20041213.
2006-12-08 08:38:33 +03:00
|
|
|
/* virtual */ void
|
2014-07-24 21:03:26 +04:00
|
|
|
nsListBoxBodyFrame::MarkIntrinsicISizesDirty()
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
|
|
|
mStringWidth = -1;
|
2014-07-24 21:03:26 +04:00
|
|
|
nsBoxFrame::MarkIntrinsicISizesDirty();
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/////////// nsBox ///////////////
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2016-04-21 07:28:35 +03:00
|
|
|
nsListBoxBodyFrame::DoXULLayout(nsBoxLayoutState& aBoxLayoutState)
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
|
|
|
if (mScrolling)
|
2011-10-17 18:59:28 +04:00
|
|
|
aBoxLayoutState.SetPaintingDisabled(true);
|
2002-01-12 04:18:10 +03:00
|
|
|
|
2016-04-21 07:28:35 +03:00
|
|
|
nsresult rv = nsBoxFrame::DoXULLayout(aBoxLayoutState);
|
2002-01-12 04:18:10 +03:00
|
|
|
|
2010-09-06 07:23:44 +04:00
|
|
|
// determine the real height for the scrollable area from the total number
|
|
|
|
// of rows, since non-visible rows don't yet have frames
|
2010-10-07 08:25:46 +04:00
|
|
|
nsRect rect(nsPoint(0, 0), GetSize());
|
|
|
|
nsOverflowAreas overflow(rect, rect);
|
2010-09-06 07:23:44 +04:00
|
|
|
if (mLayoutManager) {
|
|
|
|
nsIFrame* childFrame = mFrames.FirstChild();
|
|
|
|
while (childFrame) {
|
2010-10-07 08:25:46 +04:00
|
|
|
ConsiderChildOverflow(overflow, childFrame);
|
2010-09-06 07:23:44 +04:00
|
|
|
childFrame = childFrame->GetNextSibling();
|
|
|
|
}
|
|
|
|
|
2016-04-21 07:28:31 +03:00
|
|
|
nsSize prefSize = mLayoutManager->GetXULPrefSize(this, aBoxLayoutState);
|
2010-10-07 08:25:46 +04:00
|
|
|
NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
|
|
|
|
nsRect& o = overflow.Overflow(otype);
|
2013-01-15 16:22:03 +04:00
|
|
|
o.height = std::max(o.height, prefSize.height);
|
2010-09-06 07:23:44 +04:00
|
|
|
}
|
|
|
|
}
|
2010-10-07 08:25:46 +04:00
|
|
|
FinishAndStoreOverflow(overflow, GetSize());
|
2010-09-06 07:23:44 +04:00
|
|
|
|
2002-01-12 04:18:10 +03:00
|
|
|
if (mScrolling)
|
2011-10-17 18:59:28 +04:00
|
|
|
aBoxLayoutState.SetPaintingDisabled(false);
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
// if we are scrolled and the row height changed
|
|
|
|
// make sure we are scrolled to a correct index.
|
2003-02-18 02:52:15 +03:00
|
|
|
if (mAdjustScroll)
|
2002-01-12 04:18:10 +03:00
|
|
|
PostReflowCallback();
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2004-11-03 05:52:16 +03:00
|
|
|
nsSize
|
2016-04-21 07:28:31 +03:00
|
|
|
nsListBoxBodyFrame::GetXULMinSizeForScrollArea(nsBoxLayoutState& aBoxLayoutState)
|
2004-11-03 05:52:16 +03:00
|
|
|
{
|
|
|
|
nsSize result(0, 0);
|
2006-04-24 09:40:11 +04:00
|
|
|
if (nsContentUtils::HasNonEmptyAttr(GetContent(), kNameSpaceID_None,
|
2006-12-26 20:47:52 +03:00
|
|
|
nsGkAtoms::sizemode)) {
|
2016-04-21 07:28:31 +03:00
|
|
|
result = GetXULPrefSize(aBoxLayoutState);
|
2004-11-03 05:52:16 +03:00
|
|
|
result.height = 0;
|
|
|
|
nsIScrollableFrame* scrollFrame = nsLayoutUtils::GetScrollableFrameFor(this);
|
|
|
|
if (scrollFrame &&
|
|
|
|
scrollFrame->GetScrollbarStyles().mVertical == NS_STYLE_OVERFLOW_AUTO) {
|
|
|
|
nsMargin scrollbars =
|
|
|
|
scrollFrame->GetDesiredScrollbarSizes(&aBoxLayoutState);
|
|
|
|
result.width += scrollbars.left + scrollbars.right;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2007-01-08 05:57:59 +03:00
|
|
|
nsSize
|
2016-04-21 07:28:31 +03:00
|
|
|
nsListBoxBodyFrame::GetXULPrefSize(nsBoxLayoutState& aBoxLayoutState)
|
2004-11-03 05:52:16 +03:00
|
|
|
{
|
2016-04-21 07:28:31 +03:00
|
|
|
nsSize pref = nsBoxFrame::GetXULPrefSize(aBoxLayoutState);
|
2004-11-03 05:52:16 +03:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t size = GetFixedRowSize();
|
2004-11-03 05:52:16 +03:00
|
|
|
if (size > -1)
|
2007-02-07 10:46:44 +03:00
|
|
|
pref.height = size*GetRowHeightAppUnits();
|
|
|
|
|
2004-11-03 05:52:16 +03:00
|
|
|
nsIScrollableFrame* scrollFrame = nsLayoutUtils::GetScrollableFrameFor(this);
|
|
|
|
if (scrollFrame &&
|
|
|
|
scrollFrame->GetScrollbarStyles().mVertical == NS_STYLE_OVERFLOW_AUTO) {
|
|
|
|
nsMargin scrollbars = scrollFrame->GetDesiredScrollbarSizes(&aBoxLayoutState);
|
2007-01-08 05:57:59 +03:00
|
|
|
pref.width += scrollbars.left + scrollbars.right;
|
2004-11-03 05:52:16 +03:00
|
|
|
}
|
2007-01-08 05:57:59 +03:00
|
|
|
return pref;
|
2004-11-03 05:52:16 +03:00
|
|
|
}
|
|
|
|
|
2002-01-12 04:18:10 +03:00
|
|
|
///////////// nsIScrollbarMediator ///////////////
|
|
|
|
|
2014-02-05 05:30:34 +04:00
|
|
|
void
|
2015-03-25 21:40:31 +03:00
|
|
|
nsListBoxBodyFrame::ScrollByPage(nsScrollbarFrame* aScrollbar, int32_t aDirection,
|
|
|
|
nsIScrollbarMediator::ScrollSnapMode aSnap)
|
2014-02-05 05:30:34 +04:00
|
|
|
{
|
2015-03-25 21:40:31 +03:00
|
|
|
// CSS Scroll Snapping is not enabled for XUL, aSnap is ignored
|
2014-02-05 05:30:34 +04:00
|
|
|
MOZ_ASSERT(aScrollbar != nullptr);
|
|
|
|
aScrollbar->SetIncrementToPage(aDirection);
|
2014-10-09 16:14:26 +04:00
|
|
|
nsWeakFrame weakFrame(this);
|
|
|
|
int32_t newPos = aScrollbar->MoveToNewPosition();
|
|
|
|
if (!weakFrame.IsAlive()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
UpdateIndex(newPos);
|
2014-02-05 05:30:34 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-03-25 21:40:31 +03:00
|
|
|
nsListBoxBodyFrame::ScrollByWhole(nsScrollbarFrame* aScrollbar, int32_t aDirection,
|
|
|
|
nsIScrollbarMediator::ScrollSnapMode aSnap)
|
2014-02-05 05:30:34 +04:00
|
|
|
{
|
2015-03-25 21:40:31 +03:00
|
|
|
// CSS Scroll Snapping is not enabled for XUL, aSnap is ignored
|
2014-10-09 16:14:26 +04:00
|
|
|
MOZ_ASSERT(aScrollbar != nullptr);
|
2014-02-05 05:30:34 +04:00
|
|
|
aScrollbar->SetIncrementToWhole(aDirection);
|
2014-10-09 16:14:26 +04:00
|
|
|
nsWeakFrame weakFrame(this);
|
|
|
|
int32_t newPos = aScrollbar->MoveToNewPosition();
|
|
|
|
if (!weakFrame.IsAlive()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
UpdateIndex(newPos);
|
2014-02-05 05:30:34 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-03-25 21:40:31 +03:00
|
|
|
nsListBoxBodyFrame::ScrollByLine(nsScrollbarFrame* aScrollbar, int32_t aDirection,
|
|
|
|
nsIScrollbarMediator::ScrollSnapMode aSnap)
|
2014-02-05 05:30:34 +04:00
|
|
|
{
|
2015-03-25 21:40:31 +03:00
|
|
|
// CSS Scroll Snapping is not enabled for XUL, aSnap is ignored
|
2014-10-09 16:14:26 +04:00
|
|
|
MOZ_ASSERT(aScrollbar != nullptr);
|
2014-02-05 05:30:34 +04:00
|
|
|
aScrollbar->SetIncrementToLine(aDirection);
|
2014-10-09 16:14:26 +04:00
|
|
|
nsWeakFrame weakFrame(this);
|
|
|
|
int32_t newPos = aScrollbar->MoveToNewPosition();
|
|
|
|
if (!weakFrame.IsAlive()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
UpdateIndex(newPos);
|
2014-02-05 05:30:34 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsListBoxBodyFrame::RepeatButtonScroll(nsScrollbarFrame* aScrollbar)
|
|
|
|
{
|
2014-10-09 16:14:26 +04:00
|
|
|
nsWeakFrame weakFrame(this);
|
|
|
|
int32_t newPos = aScrollbar->MoveToNewPosition();
|
|
|
|
if (!weakFrame.IsAlive()) {
|
|
|
|
return;
|
2014-02-05 05:30:34 +04:00
|
|
|
}
|
2014-10-09 16:14:26 +04:00
|
|
|
UpdateIndex(newPos);
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t
|
|
|
|
nsListBoxBodyFrame::ToRowIndex(nscoord aPos) const
|
|
|
|
{
|
|
|
|
return NS_roundf(float(std::max(aPos, 0)) / mRowHeight);
|
2014-02-05 05:30:34 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsListBoxBodyFrame::ThumbMoved(nsScrollbarFrame* aScrollbar,
|
|
|
|
nscoord aOldPos,
|
|
|
|
nscoord aNewPos)
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
2008-06-20 08:07:37 +04:00
|
|
|
if (mScrolling || mRowHeight == 0)
|
2014-02-05 05:30:34 +04:00
|
|
|
return;
|
2002-01-12 04:18:10 +03:00
|
|
|
|
2014-10-09 16:14:26 +04:00
|
|
|
int32_t newIndex = ToRowIndex(aNewPos);
|
|
|
|
if (newIndex == mCurrentIndex) {
|
2014-02-05 05:30:34 +04:00
|
|
|
return;
|
2014-10-09 16:14:26 +04:00
|
|
|
}
|
|
|
|
int32_t rowDelta = newIndex - mCurrentIndex;
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
nsListScrollSmoother* smoother = GetSmoother();
|
|
|
|
|
|
|
|
// if we can't scroll the rows in time then start a timer. We will eat
|
|
|
|
// events until the user stops moving and the timer stops.
|
2014-10-09 16:14:26 +04:00
|
|
|
if (smoother->IsRunning() || Abs(rowDelta)*mTimePerRow > USER_TIME_THRESHOLD) {
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
smoother->Stop();
|
|
|
|
|
2014-10-09 16:14:26 +04:00
|
|
|
smoother->mDelta = rowDelta;
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
smoother->Start();
|
|
|
|
|
2014-02-05 05:30:34 +04:00
|
|
|
return;
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
smoother->Stop();
|
|
|
|
|
|
|
|
mCurrentIndex = newIndex;
|
|
|
|
smoother->mDelta = 0;
|
|
|
|
|
|
|
|
if (mCurrentIndex < 0) {
|
|
|
|
mCurrentIndex = 0;
|
2014-02-05 05:30:34 +04:00
|
|
|
return;
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
2014-10-09 16:14:26 +04:00
|
|
|
InternalPositionChanged(rowDelta < 0, Abs(rowDelta));
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
2014-02-05 05:30:34 +04:00
|
|
|
void
|
2011-09-29 10:19:26 +04:00
|
|
|
nsListBoxBodyFrame::VisibilityChanged(bool aVisible)
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
2008-06-20 08:07:37 +04:00
|
|
|
if (mRowHeight == 0)
|
2014-02-05 05:30:34 +04:00
|
|
|
return;
|
2008-06-20 08:07:37 +04:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t lastPageTopRow = GetRowCount() - (GetAvailableHeight() / mRowHeight);
|
2004-02-27 01:56:15 +03:00
|
|
|
if (lastPageTopRow < 0)
|
|
|
|
lastPageTopRow = 0;
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t delta = mCurrentIndex - lastPageTopRow;
|
2004-02-27 01:56:15 +03:00
|
|
|
if (delta > 0) {
|
|
|
|
mCurrentIndex = lastPageTopRow;
|
2011-10-17 18:59:28 +04:00
|
|
|
InternalPositionChanged(true, delta);
|
2004-02-27 01:56:15 +03:00
|
|
|
}
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
2014-02-14 10:40:53 +04:00
|
|
|
nsIFrame*
|
|
|
|
nsListBoxBodyFrame::GetScrollbarBox(bool aVertical)
|
|
|
|
{
|
|
|
|
nsIScrollableFrame* scrollFrame = nsLayoutUtils::GetScrollableFrameFor(this);
|
|
|
|
return scrollFrame ? scrollFrame->GetScrollbarBox(true) : nullptr;
|
|
|
|
}
|
|
|
|
|
2014-02-05 05:30:34 +04:00
|
|
|
void
|
2014-10-09 16:14:26 +04:00
|
|
|
nsListBoxBodyFrame::UpdateIndex(int32_t aNewPos)
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
2014-10-09 16:14:26 +04:00
|
|
|
int32_t newIndex = ToRowIndex(nsPresContext::CSSPixelsToAppUnits(aNewPos));
|
|
|
|
if (newIndex == mCurrentIndex) {
|
2014-02-05 05:30:34 +04:00
|
|
|
return;
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
2014-10-09 16:14:26 +04:00
|
|
|
bool up = newIndex < mCurrentIndex;
|
|
|
|
int32_t indexDelta = Abs(newIndex - mCurrentIndex);
|
|
|
|
mCurrentIndex = newIndex;
|
|
|
|
InternalPositionChanged(up, indexDelta);
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
2014-02-05 05:30:34 +04:00
|
|
|
|
2002-01-12 04:18:10 +03:00
|
|
|
///////////// nsIReflowCallback ///////////////
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2007-03-05 04:39:53 +03:00
|
|
|
nsListBoxBodyFrame::ReflowFinished()
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
2009-01-17 20:47:57 +03:00
|
|
|
nsAutoScriptBlocker scriptBlocker;
|
2002-01-12 04:18:10 +03:00
|
|
|
// now create or destroy any rows as needed
|
2005-02-05 06:32:17 +03:00
|
|
|
CreateRows();
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
// keep scrollbar in sync
|
|
|
|
if (mAdjustScroll) {
|
|
|
|
VerticalScroll(mYPosition);
|
2011-10-17 18:59:28 +04:00
|
|
|
mAdjustScroll = false;
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// if the row height changed then mark everything as a style change.
|
|
|
|
// That will dirty the entire listbox
|
|
|
|
if (mRowHeightWasSet) {
|
2007-03-31 01:11:41 +04:00
|
|
|
PresContext()->PresShell()->
|
2007-05-06 23:16:51 +04:00
|
|
|
FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t pos = mCurrentIndex * mRowHeight;
|
2002-01-12 04:18:10 +03:00
|
|
|
if (mYPosition != pos)
|
2011-10-17 18:59:28 +04:00
|
|
|
mAdjustScroll = true;
|
|
|
|
mRowHeightWasSet = false;
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
mReflowCallbackPosted = false;
|
|
|
|
return true;
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
2007-12-01 10:22:44 +03:00
|
|
|
void
|
|
|
|
nsListBoxBodyFrame::ReflowCallbackCanceled()
|
|
|
|
{
|
2011-10-17 18:59:28 +04:00
|
|
|
mReflowCallbackPosted = false;
|
2007-12-01 10:22:44 +03:00
|
|
|
}
|
|
|
|
|
2014-10-15 00:15:21 +04:00
|
|
|
///////// ListBoxObject ///////////////
|
2002-01-12 04:18:10 +03:00
|
|
|
|
2014-10-15 00:15:21 +04:00
|
|
|
int32_t
|
|
|
|
nsListBoxBodyFrame::GetNumberOfVisibleRows()
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
2014-10-15 00:15:21 +04:00
|
|
|
return mRowHeight ? GetAvailableHeight() / mRowHeight : 0;
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
2014-10-15 00:15:21 +04:00
|
|
|
int32_t
|
|
|
|
nsListBoxBodyFrame::GetIndexOfFirstVisibleRow()
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
2014-10-15 00:15:21 +04:00
|
|
|
return mCurrentIndex;
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
2008-10-28 08:50:19 +03:00
|
|
|
nsresult
|
2012-08-22 19:56:38 +04:00
|
|
|
nsListBoxBodyFrame::EnsureIndexIsVisible(int32_t aRowIndex)
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
|
|
|
if (aRowIndex < 0)
|
|
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t rows = 0;
|
2002-01-12 04:18:10 +03:00
|
|
|
if (mRowHeight)
|
|
|
|
rows = GetAvailableHeight()/mRowHeight;
|
2004-02-27 01:56:15 +03:00
|
|
|
if (rows <= 0)
|
|
|
|
rows = 1;
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t bottomIndex = mCurrentIndex + rows;
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
// if row is visible, ignore
|
|
|
|
if (mCurrentIndex <= aRowIndex && aRowIndex < bottomIndex)
|
|
|
|
return NS_OK;
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t delta;
|
2002-01-12 04:18:10 +03:00
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool up = aRowIndex < mCurrentIndex;
|
2002-01-12 04:18:10 +03:00
|
|
|
if (up) {
|
|
|
|
delta = mCurrentIndex - aRowIndex;
|
|
|
|
mCurrentIndex = aRowIndex;
|
|
|
|
}
|
|
|
|
else {
|
2009-06-26 23:31:16 +04:00
|
|
|
// Check to be sure we're not scrolling off the bottom of the tree
|
|
|
|
if (aRowIndex >= GetRowCount())
|
|
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
|
|
|
2002-01-12 04:18:10 +03:00
|
|
|
// Bring it just into view.
|
|
|
|
delta = 1 + (aRowIndex-bottomIndex);
|
|
|
|
mCurrentIndex += delta;
|
|
|
|
}
|
|
|
|
|
2007-08-22 06:57:06 +04:00
|
|
|
// Safe to not go off an event here, since this is coming from the
|
|
|
|
// box object.
|
|
|
|
DoInternalPositionChangedSync(up, delta);
|
2002-01-12 04:18:10 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-10-28 08:50:19 +03:00
|
|
|
nsresult
|
2012-08-22 19:56:38 +04:00
|
|
|
nsListBoxBodyFrame::ScrollByLines(int32_t aNumLines)
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
2014-10-15 00:15:21 +04:00
|
|
|
int32_t scrollIndex = GetIndexOfFirstVisibleRow(),
|
|
|
|
visibleRows = GetNumberOfVisibleRows();
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
scrollIndex += aNumLines;
|
|
|
|
|
|
|
|
if (scrollIndex < 0)
|
|
|
|
scrollIndex = 0;
|
|
|
|
else {
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t numRows = GetRowCount();
|
|
|
|
int32_t lastPageTopRow = numRows - visibleRows;
|
2002-01-12 04:18:10 +03:00
|
|
|
if (scrollIndex > lastPageTopRow)
|
|
|
|
scrollIndex = lastPageTopRow;
|
|
|
|
}
|
|
|
|
|
|
|
|
ScrollToIndex(scrollIndex);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// walks the DOM to get the zero-based row index of the content
|
2008-10-28 08:50:19 +03:00
|
|
|
nsresult
|
2012-08-22 19:56:38 +04:00
|
|
|
nsListBoxBodyFrame::GetIndexOfItem(nsIDOMElement* aItem, int32_t* _retval)
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
2007-02-16 17:23:35 +03:00
|
|
|
if (aItem) {
|
|
|
|
*_retval = 0;
|
|
|
|
nsCOMPtr<nsIContent> itemContent(do_QueryInterface(aItem));
|
2002-01-12 04:18:10 +03:00
|
|
|
|
2013-05-02 02:50:08 +04:00
|
|
|
FlattenedChildIterator iter(mContent);
|
|
|
|
for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
|
2007-02-16 17:23:35 +03:00
|
|
|
// we hit a list row, count it
|
2015-03-03 14:09:00 +03:00
|
|
|
if (child->IsXULElement(nsGkAtoms::listitem)) {
|
2007-02-16 17:23:35 +03:00
|
|
|
// is this it?
|
|
|
|
if (child == itemContent)
|
|
|
|
return NS_OK;
|
2003-11-19 04:20:56 +03:00
|
|
|
|
2007-02-16 17:23:35 +03:00
|
|
|
++(*_retval);
|
|
|
|
}
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// not found
|
2007-02-16 17:23:35 +03:00
|
|
|
*_retval = -1;
|
|
|
|
return NS_OK;
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
2008-10-28 08:50:19 +03:00
|
|
|
nsresult
|
2012-08-22 19:56:38 +04:00
|
|
|
nsListBoxBodyFrame::GetItemAtIndex(int32_t aIndex, nsIDOMElement** aItem)
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
2012-07-30 18:20:58 +04:00
|
|
|
*aItem = nullptr;
|
2002-01-12 04:18:10 +03:00
|
|
|
if (aIndex < 0)
|
2007-02-16 17:23:35 +03:00
|
|
|
return NS_OK;
|
2013-05-02 02:50:08 +04:00
|
|
|
|
2013-08-02 20:09:54 +04:00
|
|
|
int32_t itemCount = 0;
|
2013-05-02 02:50:08 +04:00
|
|
|
FlattenedChildIterator iter(mContent);
|
|
|
|
for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
|
2007-02-16 17:23:35 +03:00
|
|
|
// we hit a list row, check if it is the one we are looking for
|
2015-03-03 14:09:00 +03:00
|
|
|
if (child->IsXULElement(nsGkAtoms::listitem)) {
|
2002-01-12 04:18:10 +03:00
|
|
|
// is this it?
|
|
|
|
if (itemCount == aIndex) {
|
2006-11-06 01:54:41 +03:00
|
|
|
return CallQueryInterface(child, aItem);
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
++itemCount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// not found
|
2007-02-16 17:23:35 +03:00
|
|
|
return NS_OK;
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/////////// nsListBoxBodyFrame ///////////////
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t
|
2002-01-12 04:18:10 +03:00
|
|
|
nsListBoxBodyFrame::GetRowCount()
|
|
|
|
{
|
|
|
|
if (mRowCount < 0)
|
|
|
|
ComputeTotalRowCount();
|
|
|
|
return mRowCount;
|
|
|
|
}
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t
|
2002-01-12 04:18:10 +03:00
|
|
|
nsListBoxBodyFrame::GetFixedRowSize()
|
|
|
|
{
|
2012-07-27 17:59:29 +04:00
|
|
|
nsresult dummy;
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
nsAutoString rows;
|
2006-12-26 20:47:52 +03:00
|
|
|
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::rows, rows);
|
2002-01-12 04:18:10 +03:00
|
|
|
if (!rows.IsEmpty())
|
|
|
|
return rows.ToInteger(&dummy);
|
|
|
|
|
2006-12-26 20:47:52 +03:00
|
|
|
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::size, rows);
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
if (!rows.IsEmpty())
|
|
|
|
return rows.ToInteger(&dummy);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsListBoxBodyFrame::SetRowHeight(nscoord aRowHeight)
|
|
|
|
{
|
|
|
|
if (aRowHeight > mRowHeight) {
|
|
|
|
mRowHeight = aRowHeight;
|
|
|
|
|
|
|
|
// signal we need to dirty everything
|
|
|
|
// and we want to be notified after reflow
|
|
|
|
// so we can create or destory rows as needed
|
2011-10-17 18:59:28 +04:00
|
|
|
mRowHeightWasSet = true;
|
2002-01-12 04:18:10 +03:00
|
|
|
PostReflowCallback();
|
2005-04-04 01:02:47 +04:00
|
|
|
}
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
nscoord
|
|
|
|
nsListBoxBodyFrame::GetAvailableHeight()
|
|
|
|
{
|
2009-09-03 08:11:49 +04:00
|
|
|
nsIScrollableFrame* scrollFrame =
|
|
|
|
nsLayoutUtils::GetScrollableFrameFor(this);
|
2007-09-25 11:12:36 +04:00
|
|
|
if (scrollFrame) {
|
2009-09-03 08:11:49 +04:00
|
|
|
return scrollFrame->GetScrollPortRect().height;
|
2007-09-25 11:12:36 +04:00
|
|
|
}
|
|
|
|
return 0;
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
nscoord
|
|
|
|
nsListBoxBodyFrame::GetYPosition()
|
|
|
|
{
|
|
|
|
return mYPosition;
|
|
|
|
}
|
|
|
|
|
|
|
|
nscoord
|
2014-07-24 21:03:26 +04:00
|
|
|
nsListBoxBodyFrame::ComputeIntrinsicISize(nsBoxLayoutState& aBoxLayoutState)
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
|
|
|
if (mStringWidth != -1)
|
|
|
|
return mStringWidth;
|
|
|
|
|
|
|
|
nscoord largestWidth = 0;
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t index = 0;
|
2002-01-12 04:18:10 +03:00
|
|
|
nsCOMPtr<nsIDOMElement> firstRowEl;
|
|
|
|
GetItemAtIndex(index, getter_AddRefs(firstRowEl));
|
|
|
|
nsCOMPtr<nsIContent> firstRowContent(do_QueryInterface(firstRowEl));
|
|
|
|
|
|
|
|
if (firstRowContent) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsStyleContext> styleContext;
|
2004-08-01 03:15:21 +04:00
|
|
|
nsPresContext *presContext = aBoxLayoutState.PresContext();
|
2004-01-28 03:18:22 +03:00
|
|
|
styleContext = presContext->StyleSet()->
|
2012-07-30 18:20:58 +04:00
|
|
|
ResolveStyleFor(firstRowContent->AsElement(), nullptr);
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
nscoord width = 0;
|
|
|
|
nsMargin margin(0,0,0,0);
|
|
|
|
|
2013-02-17 01:51:02 +04:00
|
|
|
if (styleContext->StylePadding()->GetPadding(margin))
|
2006-12-20 04:23:45 +03:00
|
|
|
width += margin.LeftRight();
|
2013-02-17 01:51:02 +04:00
|
|
|
width += styleContext->StyleBorder()->GetComputedBorder().LeftRight();
|
|
|
|
if (styleContext->StyleMargin()->GetMargin(margin))
|
2006-12-20 04:23:45 +03:00
|
|
|
width += margin.LeftRight();
|
2002-01-12 04:18:10 +03:00
|
|
|
|
2013-05-02 02:50:08 +04:00
|
|
|
FlattenedChildIterator iter(mContent);
|
|
|
|
for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
|
2015-03-03 14:09:00 +03:00
|
|
|
if (child->IsXULElement(nsGkAtoms::listitem)) {
|
2011-04-08 05:04:40 +04:00
|
|
|
nsRenderingContext* rendContext = aBoxLayoutState.GetRenderingContext();
|
2002-01-12 04:18:10 +03:00
|
|
|
if (rendContext) {
|
|
|
|
nsAutoString value;
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t textCount = child->GetChildCount();
|
|
|
|
for (uint32_t j = 0; j < textCount; ++j) {
|
2006-07-19 08:36:36 +04:00
|
|
|
nsIContent* text = child->GetChildAt(j);
|
2006-05-05 10:52:21 +04:00
|
|
|
if (text && text->IsNodeOfType(nsINode::eTEXT)) {
|
2003-09-27 08:18:26 +04:00
|
|
|
text->AppendTextTo(value);
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
}
|
2007-08-07 23:07:43 +04:00
|
|
|
|
2016-03-17 08:55:48 +03:00
|
|
|
RefPtr<nsFontMetrics> fm =
|
|
|
|
nsLayoutUtils::GetFontMetricsForStyleContext(styleContext);
|
2002-01-12 04:18:10 +03:00
|
|
|
|
2007-01-23 05:58:55 +03:00
|
|
|
nscoord textWidth =
|
2014-10-26 20:57:49 +03:00
|
|
|
nsLayoutUtils::AppUnitWidthOfStringBidi(value, this, *fm,
|
|
|
|
*rendContext);
|
2002-01-12 04:18:10 +03:00
|
|
|
textWidth += width;
|
|
|
|
|
|
|
|
if (textWidth > largestWidth)
|
|
|
|
largestWidth = textWidth;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mStringWidth = largestWidth;
|
|
|
|
return mStringWidth;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsListBoxBodyFrame::ComputeTotalRowCount()
|
|
|
|
{
|
2006-11-06 01:54:41 +03:00
|
|
|
mRowCount = 0;
|
2013-05-02 02:50:08 +04:00
|
|
|
FlattenedChildIterator iter(mContent);
|
|
|
|
for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
|
2015-03-03 14:09:00 +03:00
|
|
|
if (child->IsXULElement(nsGkAtoms::listitem)) {
|
2002-01-12 04:18:10 +03:00
|
|
|
++mRowCount;
|
2013-05-02 02:50:08 +04:00
|
|
|
}
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsListBoxBodyFrame::PostReflowCallback()
|
|
|
|
{
|
|
|
|
if (!mReflowCallbackPosted) {
|
2011-10-17 18:59:28 +04:00
|
|
|
mReflowCallbackPosted = true;
|
2007-03-31 01:11:41 +04:00
|
|
|
PresContext()->PresShell()->PostReflowCallback(this);
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
////////// scrolling
|
|
|
|
|
2008-10-28 08:50:19 +03:00
|
|
|
nsresult
|
2012-08-22 19:56:38 +04:00
|
|
|
nsListBoxBodyFrame::ScrollToIndex(int32_t aRowIndex)
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
|
|
|
if (( aRowIndex < 0 ) || (mRowHeight == 0))
|
|
|
|
return NS_OK;
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t newIndex = aRowIndex;
|
|
|
|
int32_t delta = mCurrentIndex > newIndex ? mCurrentIndex - newIndex : newIndex - mCurrentIndex;
|
2011-09-29 10:19:26 +04:00
|
|
|
bool up = newIndex < mCurrentIndex;
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
// Check to be sure we're not scrolling off the bottom of the tree
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t lastPageTopRow = GetRowCount() - (GetAvailableHeight() / mRowHeight);
|
2002-01-12 04:18:10 +03:00
|
|
|
if (lastPageTopRow < 0)
|
|
|
|
lastPageTopRow = 0;
|
|
|
|
|
|
|
|
if (aRowIndex > lastPageTopRow)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
mCurrentIndex = newIndex;
|
2007-08-22 06:57:06 +04:00
|
|
|
|
2009-06-11 21:09:33 +04:00
|
|
|
nsWeakFrame weak(this);
|
|
|
|
|
2007-08-22 06:57:06 +04:00
|
|
|
// Since we're going to flush anyway, we need to not do this off an event
|
|
|
|
DoInternalPositionChangedSync(up, delta);
|
2002-01-12 04:18:10 +03:00
|
|
|
|
2009-06-11 21:09:33 +04:00
|
|
|
if (!weak.IsAlive()) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2002-01-12 04:18:10 +03:00
|
|
|
// This change has to happen immediately.
|
|
|
|
// Flush any pending reflow commands.
|
2007-08-22 06:57:06 +04:00
|
|
|
// XXXbz why, exactly?
|
2014-08-23 00:11:27 +04:00
|
|
|
mContent->GetComposedDoc()->FlushPendingNotifications(Flush_Layout);
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-08-22 06:57:06 +04:00
|
|
|
nsresult
|
2002-01-12 04:18:10 +03:00
|
|
|
nsListBoxBodyFrame::InternalPositionChangedCallback()
|
|
|
|
{
|
|
|
|
nsListScrollSmoother* smoother = GetSmoother();
|
|
|
|
|
|
|
|
if (smoother->mDelta == 0)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
mCurrentIndex += smoother->mDelta;
|
|
|
|
|
|
|
|
if (mCurrentIndex < 0)
|
|
|
|
mCurrentIndex = 0;
|
|
|
|
|
2007-08-22 06:57:06 +04:00
|
|
|
return DoInternalPositionChangedSync(smoother->mDelta < 0,
|
|
|
|
smoother->mDelta < 0 ?
|
|
|
|
-smoother->mDelta : smoother->mDelta);
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
2007-08-22 06:57:06 +04:00
|
|
|
nsresult
|
2012-08-22 19:56:38 +04:00
|
|
|
nsListBoxBodyFrame::InternalPositionChanged(bool aUp, int32_t aDelta)
|
2007-08-22 06:57:06 +04:00
|
|
|
{
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsPositionChangedEvent> ev =
|
2007-08-22 06:57:06 +04:00
|
|
|
new nsPositionChangedEvent(this, aUp, aDelta);
|
|
|
|
nsresult rv = NS_DispatchToCurrentThread(ev);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
if (!mPendingPositionChangeEvents.AppendElement(ev)) {
|
|
|
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
ev->Revoke();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2012-08-22 19:56:38 +04:00
|
|
|
nsListBoxBodyFrame::DoInternalPositionChangedSync(bool aUp, int32_t aDelta)
|
2007-08-22 06:57:06 +04:00
|
|
|
{
|
|
|
|
nsWeakFrame weak(this);
|
|
|
|
|
|
|
|
// Process all the pending position changes first
|
2015-10-18 08:24:48 +03:00
|
|
|
nsTArray< RefPtr<nsPositionChangedEvent> > temp;
|
2007-08-22 06:57:06 +04:00
|
|
|
temp.SwapElements(mPendingPositionChangeEvents);
|
2012-08-22 19:56:38 +04:00
|
|
|
for (uint32_t i = 0; i < temp.Length(); ++i) {
|
2009-06-11 21:09:33 +04:00
|
|
|
if (weak.IsAlive()) {
|
|
|
|
temp[i]->Run();
|
|
|
|
}
|
2007-08-22 06:57:06 +04:00
|
|
|
temp[i]->Revoke();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!weak.IsAlive()) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return DoInternalPositionChanged(aUp, aDelta);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2012-08-22 19:56:38 +04:00
|
|
|
nsListBoxBodyFrame::DoInternalPositionChanged(bool aUp, int32_t aDelta)
|
2007-08-22 06:57:06 +04:00
|
|
|
{
|
2002-01-12 04:18:10 +03:00
|
|
|
if (aDelta == 0)
|
|
|
|
return NS_OK;
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsPresContext> presContext(PresContext());
|
2005-12-15 06:30:17 +03:00
|
|
|
nsBoxLayoutState state(presContext);
|
2004-09-28 22:37:50 +04:00
|
|
|
|
2002-01-12 04:18:10 +03:00
|
|
|
// begin timing how long it takes to scroll a row
|
|
|
|
PRTime start = PR_Now();
|
|
|
|
|
2007-08-22 06:57:06 +04:00
|
|
|
nsWeakFrame weakThis(this);
|
2014-08-23 00:11:27 +04:00
|
|
|
mContent->GetComposedDoc()->FlushPendingNotifications(Flush_Layout);
|
2007-08-22 06:57:06 +04:00
|
|
|
if (!weakThis.IsAlive()) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2002-01-12 04:18:10 +03:00
|
|
|
|
2009-06-26 23:31:16 +04:00
|
|
|
{
|
|
|
|
nsAutoScriptBlocker scriptBlocker;
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t visibleRows = 0;
|
2009-06-26 23:31:16 +04:00
|
|
|
if (mRowHeight)
|
|
|
|
visibleRows = GetAvailableHeight()/mRowHeight;
|
2002-01-12 04:18:10 +03:00
|
|
|
|
2009-06-26 23:31:16 +04:00
|
|
|
if (aDelta < visibleRows) {
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t loseRows = aDelta;
|
2009-06-26 23:31:16 +04:00
|
|
|
if (aUp) {
|
|
|
|
// scrolling up, destroy rows from the bottom downwards
|
|
|
|
ReverseDestroyRows(loseRows);
|
|
|
|
mRowsToPrepend += aDelta;
|
2012-07-30 18:20:58 +04:00
|
|
|
mLinkupFrame = nullptr;
|
2009-06-26 23:31:16 +04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// scrolling down, destroy rows from the top upwards
|
|
|
|
DestroyRows(loseRows);
|
|
|
|
mRowsToPrepend = 0;
|
|
|
|
}
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
else {
|
2009-06-26 23:31:16 +04:00
|
|
|
// We have scrolled so much that all of our current frames will
|
|
|
|
// go off screen, so blow them all away. Weeee!
|
|
|
|
nsIFrame *currBox = mFrames.FirstChild();
|
|
|
|
nsCSSFrameConstructor* fc = presContext->PresShell()->FrameConstructor();
|
|
|
|
fc->BeginUpdate();
|
|
|
|
while (currBox) {
|
|
|
|
nsIFrame *nextBox = currBox->GetNextSibling();
|
|
|
|
RemoveChildFrame(state, currBox);
|
|
|
|
currBox = nextBox;
|
|
|
|
}
|
|
|
|
fc->EndUpdate();
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
2009-06-26 23:31:16 +04:00
|
|
|
// clear frame markers so that CreateRows will re-create
|
2012-07-30 18:20:58 +04:00
|
|
|
mTopFrame = mBottomFrame = nullptr;
|
2002-01-12 04:18:10 +03:00
|
|
|
|
2009-06-26 23:31:16 +04:00
|
|
|
mYPosition = mCurrentIndex*mRowHeight;
|
2011-10-17 18:59:28 +04:00
|
|
|
mScrolling = true;
|
2009-06-26 23:31:16 +04:00
|
|
|
presContext->PresShell()->
|
|
|
|
FrameNeedsReflow(this, nsIPresShell::eResize, NS_FRAME_HAS_DIRTY_CHILDREN);
|
|
|
|
}
|
|
|
|
if (!weakThis.IsAlive()) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2004-05-28 02:08:42 +04:00
|
|
|
// Flush calls CreateRows
|
|
|
|
// XXXbz there has to be a better way to do this than flushing!
|
2007-08-22 06:57:06 +04:00
|
|
|
presContext->PresShell()->FlushPendingNotifications(Flush_Layout);
|
|
|
|
if (!weakThis.IsAlive()) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
mScrolling = false;
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
VerticalScroll(mYPosition);
|
|
|
|
|
|
|
|
PRTime end = PR_Now();
|
|
|
|
|
2012-10-12 21:29:10 +04:00
|
|
|
int32_t newTime = int32_t(end - start) / aDelta;
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
// average old and new
|
|
|
|
mTimePerRow = (newTime + mTimePerRow)/2;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsListScrollSmoother*
|
|
|
|
nsListBoxBodyFrame::GetSmoother()
|
|
|
|
{
|
|
|
|
if (!mScrollSmoother) {
|
|
|
|
mScrollSmoother = new nsListScrollSmoother(this);
|
|
|
|
NS_ASSERTION(mScrollSmoother, "out of memory");
|
|
|
|
NS_IF_ADDREF(mScrollSmoother);
|
|
|
|
}
|
|
|
|
|
|
|
|
return mScrollSmoother;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-08-22 19:56:38 +04:00
|
|
|
nsListBoxBodyFrame::VerticalScroll(int32_t aPosition)
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
2005-04-04 01:02:47 +04:00
|
|
|
nsIScrollableFrame* scrollFrame
|
|
|
|
= nsLayoutUtils::GetScrollableFrameFor(this);
|
2007-09-25 11:12:36 +04:00
|
|
|
if (!scrollFrame) {
|
|
|
|
return;
|
|
|
|
}
|
2002-01-12 04:18:10 +03:00
|
|
|
|
2004-09-06 06:44:43 +04:00
|
|
|
nsPoint scrollPosition = scrollFrame->GetScrollPosition();
|
2002-01-12 04:18:10 +03:00
|
|
|
|
2013-08-09 02:04:59 +04:00
|
|
|
nsWeakFrame weakFrame(this);
|
2009-09-01 08:11:11 +04:00
|
|
|
scrollFrame->ScrollTo(nsPoint(scrollPosition.x, aPosition),
|
|
|
|
nsIScrollableFrame::INSTANT);
|
2013-08-09 02:04:59 +04:00
|
|
|
if (!weakFrame.IsAlive()) {
|
|
|
|
return;
|
|
|
|
}
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
mYPosition = aPosition;
|
|
|
|
}
|
|
|
|
|
|
|
|
////////// frame and box retrieval
|
|
|
|
|
|
|
|
nsIFrame*
|
|
|
|
nsListBoxBodyFrame::GetFirstFrame()
|
|
|
|
{
|
|
|
|
mTopFrame = mFrames.FirstChild();
|
|
|
|
return mTopFrame;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIFrame*
|
|
|
|
nsListBoxBodyFrame::GetLastFrame()
|
|
|
|
{
|
|
|
|
return mFrames.LastChild();
|
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2009-01-09 03:11:30 +03:00
|
|
|
nsListBoxBodyFrame::SupportsOrdinalsInChildren()
|
|
|
|
{
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2009-01-09 03:11:30 +03:00
|
|
|
}
|
|
|
|
|
2002-01-12 04:18:10 +03:00
|
|
|
////////// lazy row creation and destruction
|
|
|
|
|
|
|
|
void
|
2005-02-05 06:32:17 +03:00
|
|
|
nsListBoxBodyFrame::CreateRows()
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
|
|
|
// Get our client rect.
|
|
|
|
nsRect clientRect;
|
2016-04-21 07:28:33 +03:00
|
|
|
GetXULClientRect(clientRect);
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
// Get the starting y position and the remaining available
|
|
|
|
// height.
|
|
|
|
nscoord availableHeight = GetAvailableHeight();
|
|
|
|
|
|
|
|
if (availableHeight <= 0) {
|
2011-09-29 10:19:26 +04:00
|
|
|
bool fixed = (GetFixedRowSize() != -1);
|
2002-01-12 04:18:10 +03:00
|
|
|
if (fixed)
|
|
|
|
availableHeight = 10;
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the first tree box. If there isn't one create one.
|
2011-09-29 10:19:26 +04:00
|
|
|
bool created = false;
|
2012-08-06 07:00:57 +04:00
|
|
|
nsIFrame* box = GetFirstItemBox(0, &created);
|
2007-02-07 10:46:44 +03:00
|
|
|
nscoord rowHeight = GetRowHeightAppUnits();
|
2002-01-12 04:18:10 +03:00
|
|
|
while (box) {
|
|
|
|
if (created && mRowsToPrepend > 0)
|
|
|
|
--mRowsToPrepend;
|
|
|
|
|
|
|
|
// if the row height is 0 then fail. Wait until someone
|
|
|
|
// laid out and sets the row height.
|
|
|
|
if (rowHeight == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
availableHeight -= rowHeight;
|
|
|
|
|
|
|
|
// should we continue? Is the enought height?
|
|
|
|
if (!ContinueReflow(availableHeight))
|
|
|
|
break;
|
|
|
|
|
|
|
|
// get the next tree box. Create one if needed.
|
|
|
|
box = GetNextItemBox(box, 0, &created);
|
|
|
|
}
|
|
|
|
|
|
|
|
mRowsToPrepend = 0;
|
2012-07-30 18:20:58 +04:00
|
|
|
mLinkupFrame = nullptr;
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-08-22 19:56:38 +04:00
|
|
|
nsListBoxBodyFrame::DestroyRows(int32_t& aRowsToLose)
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
|
|
|
// We need to destroy frames until our row count has been properly
|
|
|
|
// reduced. A reflow will then pick up and create the new frames.
|
|
|
|
nsIFrame* childFrame = GetFirstFrame();
|
2007-03-31 01:11:41 +04:00
|
|
|
nsBoxLayoutState state(PresContext());
|
2004-09-28 22:37:50 +04:00
|
|
|
|
2007-10-09 06:34:58 +04:00
|
|
|
nsCSSFrameConstructor* fc = PresContext()->PresShell()->FrameConstructor();
|
|
|
|
fc->BeginUpdate();
|
2002-01-12 04:18:10 +03:00
|
|
|
while (childFrame && aRowsToLose > 0) {
|
|
|
|
--aRowsToLose;
|
|
|
|
|
2004-09-28 22:37:50 +04:00
|
|
|
nsIFrame* nextFrame = childFrame->GetNextSibling();
|
|
|
|
RemoveChildFrame(state, childFrame);
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
mTopFrame = childFrame = nextFrame;
|
|
|
|
}
|
2007-10-09 06:34:58 +04:00
|
|
|
fc->EndUpdate();
|
2004-09-28 22:37:50 +04:00
|
|
|
|
2007-03-31 01:11:41 +04:00
|
|
|
PresContext()->PresShell()->
|
2007-05-06 23:16:51 +04:00
|
|
|
FrameNeedsReflow(this, nsIPresShell::eTreeChange,
|
|
|
|
NS_FRAME_HAS_DIRTY_CHILDREN);
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-08-22 19:56:38 +04:00
|
|
|
nsListBoxBodyFrame::ReverseDestroyRows(int32_t& aRowsToLose)
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
|
|
|
// We need to destroy frames until our row count has been properly
|
|
|
|
// reduced. A reflow will then pick up and create the new frames.
|
|
|
|
nsIFrame* childFrame = GetLastFrame();
|
2007-03-31 01:11:41 +04:00
|
|
|
nsBoxLayoutState state(PresContext());
|
2004-09-28 22:37:50 +04:00
|
|
|
|
2007-10-09 06:34:58 +04:00
|
|
|
nsCSSFrameConstructor* fc = PresContext()->PresShell()->FrameConstructor();
|
|
|
|
fc->BeginUpdate();
|
2002-01-12 04:18:10 +03:00
|
|
|
while (childFrame && aRowsToLose > 0) {
|
|
|
|
--aRowsToLose;
|
|
|
|
|
|
|
|
nsIFrame* prevFrame;
|
2009-10-02 20:27:37 +04:00
|
|
|
prevFrame = childFrame->GetPrevSibling();
|
2004-09-28 22:37:50 +04:00
|
|
|
RemoveChildFrame(state, childFrame);
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
mBottomFrame = childFrame = prevFrame;
|
|
|
|
}
|
2007-10-09 06:34:58 +04:00
|
|
|
fc->EndUpdate();
|
2004-09-28 22:37:50 +04:00
|
|
|
|
2007-03-31 01:11:41 +04:00
|
|
|
PresContext()->PresShell()->
|
2007-05-06 23:16:51 +04:00
|
|
|
FrameNeedsReflow(this, nsIPresShell::eTreeChange,
|
|
|
|
NS_FRAME_HAS_DIRTY_CHILDREN);
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
2011-07-15 18:24:58 +04:00
|
|
|
static bool
|
|
|
|
IsListItemChild(nsListBoxBodyFrame* aParent, nsIContent* aChild,
|
|
|
|
nsIFrame** aChildFrame)
|
|
|
|
{
|
2012-07-30 18:20:58 +04:00
|
|
|
*aChildFrame = nullptr;
|
2015-03-03 14:09:00 +03:00
|
|
|
if (!aChild->IsXULElement(nsGkAtoms::listitem)) {
|
2011-07-15 18:24:58 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
nsIFrame* existingFrame = aChild->GetPrimaryFrame();
|
|
|
|
if (existingFrame && existingFrame->GetParent() != aParent) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
*aChildFrame = existingFrame;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2002-01-12 04:18:10 +03:00
|
|
|
//
|
2012-08-06 07:00:57 +04:00
|
|
|
// Get the nsIFrame for the first visible listitem, and if none exists,
|
2002-01-12 04:18:10 +03:00
|
|
|
// create one.
|
|
|
|
//
|
2012-08-06 07:00:57 +04:00
|
|
|
nsIFrame*
|
2012-08-22 19:56:38 +04:00
|
|
|
nsListBoxBodyFrame::GetFirstItemBox(int32_t aOffset, bool* aCreated)
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
|
|
|
if (aCreated)
|
2011-10-17 18:59:28 +04:00
|
|
|
*aCreated = false;
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
// Clear ourselves out.
|
|
|
|
mBottomFrame = mTopFrame;
|
|
|
|
|
|
|
|
if (mTopFrame) {
|
2016-04-21 07:28:30 +03:00
|
|
|
return mTopFrame->IsXULBoxFrame() ? mTopFrame : nullptr;
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// top frame was cleared out
|
|
|
|
mTopFrame = GetFirstFrame();
|
|
|
|
mBottomFrame = mTopFrame;
|
|
|
|
|
|
|
|
if (mTopFrame && mRowsToPrepend <= 0) {
|
2016-04-21 07:28:30 +03:00
|
|
|
return mTopFrame->IsXULBoxFrame() ? mTopFrame : nullptr;
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// At this point, we either have no frames at all,
|
|
|
|
// or the user has scrolled upwards, leaving frames
|
|
|
|
// to be created at the top. Let's determine which
|
|
|
|
// content needs a new frame first.
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> startContent;
|
|
|
|
if (mTopFrame && mRowsToPrepend > 0) {
|
|
|
|
// We need to insert rows before the top frame
|
2003-08-04 16:39:51 +04:00
|
|
|
nsIContent* topContent = mTopFrame->GetContent();
|
2003-07-29 01:25:13 +04:00
|
|
|
nsIContent* topParent = topContent->GetParent();
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t contentIndex = topParent->IndexOf(topContent);
|
2002-01-12 04:18:10 +03:00
|
|
|
contentIndex -= aOffset;
|
|
|
|
if (contentIndex < 0)
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2003-09-27 08:18:26 +04:00
|
|
|
startContent = topParent->GetChildAt(contentIndex - mRowsToPrepend);
|
2002-01-12 04:18:10 +03:00
|
|
|
} else {
|
|
|
|
// This will be the first item frame we create. Use the content
|
|
|
|
// at the current index, which is the first index scrolled into view
|
|
|
|
GetListItemContentAt(mCurrentIndex+aOffset, getter_AddRefs(startContent));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (startContent) {
|
2011-07-15 18:24:58 +04:00
|
|
|
nsIFrame* existingFrame;
|
|
|
|
if (!IsListItemChild(this, startContent, &existingFrame)) {
|
|
|
|
return GetFirstItemBox(++aOffset, aCreated);
|
|
|
|
}
|
|
|
|
if (existingFrame) {
|
2016-04-21 07:28:30 +03:00
|
|
|
return existingFrame->IsXULBoxFrame() ? existingFrame : nullptr;
|
2011-07-15 18:24:58 +04:00
|
|
|
}
|
|
|
|
|
2002-01-12 04:18:10 +03:00
|
|
|
// Either append the new frame, or prepend it (at index 0)
|
|
|
|
// XXX check here if frame was even created, it may not have been if
|
|
|
|
// display: none was on listitem content
|
2011-09-29 10:19:26 +04:00
|
|
|
bool isAppend = mRowsToPrepend <= 0;
|
2005-12-16 05:56:36 +03:00
|
|
|
|
2007-03-31 01:11:41 +04:00
|
|
|
nsPresContext* presContext = PresContext();
|
2005-12-16 05:56:36 +03:00
|
|
|
nsCSSFrameConstructor* fc = presContext->PresShell()->FrameConstructor();
|
2012-07-30 18:20:58 +04:00
|
|
|
nsIFrame* topFrame = nullptr;
|
2016-01-06 03:08:17 +03:00
|
|
|
fc->CreateListBoxContent(this, nullptr, startContent, &topFrame, isAppend);
|
2006-11-16 18:45:55 +03:00
|
|
|
mTopFrame = topFrame;
|
2002-01-12 04:18:10 +03:00
|
|
|
if (mTopFrame) {
|
|
|
|
if (aCreated)
|
2011-10-17 18:59:28 +04:00
|
|
|
*aCreated = true;
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
mBottomFrame = mTopFrame;
|
|
|
|
|
2016-04-21 07:28:30 +03:00
|
|
|
return mTopFrame->IsXULBoxFrame() ? mTopFrame : nullptr;
|
2002-01-12 04:18:10 +03:00
|
|
|
} else
|
|
|
|
return GetFirstItemBox(++aOffset, 0);
|
|
|
|
}
|
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
2012-08-06 07:00:57 +04:00
|
|
|
// Get the nsIFrame for the next visible listitem after aBox, and if none
|
2002-01-12 04:18:10 +03:00
|
|
|
// exists, create one.
|
|
|
|
//
|
2012-08-06 07:00:57 +04:00
|
|
|
nsIFrame*
|
2012-08-22 19:56:38 +04:00
|
|
|
nsListBoxBodyFrame::GetNextItemBox(nsIFrame* aBox, int32_t aOffset,
|
2011-09-29 10:19:26 +04:00
|
|
|
bool* aCreated)
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
|
|
|
if (aCreated)
|
2011-10-17 18:59:28 +04:00
|
|
|
*aCreated = false;
|
2002-01-12 04:18:10 +03:00
|
|
|
|
2004-09-28 22:37:50 +04:00
|
|
|
nsIFrame* result = aBox->GetNextSibling();
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
if (!result || result == mLinkupFrame || mRowsToPrepend > 0) {
|
|
|
|
// No result found. See if there's a content node that wants a frame.
|
2004-09-28 22:37:50 +04:00
|
|
|
nsIContent* prevContent = aBox->GetContent();
|
2003-07-29 01:25:13 +04:00
|
|
|
nsIContent* parentContent = prevContent->GetParent();
|
2003-09-27 08:18:26 +04:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t i = parentContent->IndexOf(prevContent);
|
2003-09-27 08:18:26 +04:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t childCount = parentContent->GetChildCount();
|
|
|
|
if (((uint32_t)i + aOffset + 1) < childCount) {
|
2002-01-12 04:18:10 +03:00
|
|
|
// There is a content node that wants a frame.
|
2003-09-27 08:18:26 +04:00
|
|
|
nsIContent *nextContent = parentContent->GetChildAt(i + aOffset + 1);
|
2002-01-12 04:18:10 +03:00
|
|
|
|
2011-07-15 18:24:58 +04:00
|
|
|
nsIFrame* existingFrame;
|
|
|
|
if (!IsListItemChild(this, nextContent, &existingFrame)) {
|
2009-08-25 16:37:07 +04:00
|
|
|
return GetNextItemBox(aBox, ++aOffset, aCreated);
|
2011-07-15 18:24:58 +04:00
|
|
|
}
|
2009-04-06 07:53:40 +04:00
|
|
|
if (!existingFrame) {
|
2009-04-03 23:44:33 +04:00
|
|
|
// Either append the new frame, or insert it after the current frame
|
2011-09-29 10:19:26 +04:00
|
|
|
bool isAppend = result != mLinkupFrame && mRowsToPrepend <= 0;
|
2012-07-30 18:20:58 +04:00
|
|
|
nsIFrame* prevFrame = isAppend ? nullptr : aBox;
|
2009-04-03 23:44:33 +04:00
|
|
|
|
2011-07-15 18:24:58 +04:00
|
|
|
nsPresContext* presContext = PresContext();
|
2009-04-03 23:44:33 +04:00
|
|
|
nsCSSFrameConstructor* fc = presContext->PresShell()->FrameConstructor();
|
2015-12-07 04:15:53 +03:00
|
|
|
fc->CreateListBoxContent(this, prevFrame, nextContent,
|
2016-01-06 03:08:17 +03:00
|
|
|
&result, isAppend);
|
2009-04-03 23:44:33 +04:00
|
|
|
|
|
|
|
if (result) {
|
|
|
|
if (aCreated)
|
2011-10-17 18:59:28 +04:00
|
|
|
*aCreated = true;
|
2009-04-03 23:44:33 +04:00
|
|
|
} else
|
|
|
|
return GetNextItemBox(aBox, ++aOffset, aCreated);
|
2009-04-06 07:53:40 +04:00
|
|
|
} else {
|
|
|
|
result = existingFrame;
|
2009-04-03 23:44:33 +04:00
|
|
|
}
|
2002-01-12 04:18:10 +03:00
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
mLinkupFrame = nullptr;
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-08-06 16:48:28 +04:00
|
|
|
if (!result)
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2002-01-12 04:18:10 +03:00
|
|
|
|
2002-08-06 16:48:28 +04:00
|
|
|
mBottomFrame = result;
|
|
|
|
|
2016-04-21 07:28:30 +03:00
|
|
|
NS_ASSERTION(!result->IsXULBoxFrame() || result->GetParent() == this,
|
2009-06-24 05:35:01 +04:00
|
|
|
"returning frame that is not in childlist");
|
|
|
|
|
2016-04-21 07:28:30 +03:00
|
|
|
return result->IsXULBoxFrame() ? result : nullptr;
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2002-01-12 04:18:10 +03:00
|
|
|
nsListBoxBodyFrame::ContinueReflow(nscoord height)
|
2011-07-19 12:30:19 +04:00
|
|
|
{
|
|
|
|
#ifdef ACCESSIBILITY
|
|
|
|
if (nsIPresShell::IsAccessibilityActive()) {
|
2006-08-14 17:38:53 +04:00
|
|
|
// Create all the frames at once so screen readers and
|
|
|
|
// onscreen keyboards can see the full list right away
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2006-08-14 17:38:53 +04:00
|
|
|
}
|
2011-07-19 12:30:19 +04:00
|
|
|
#endif
|
2006-08-14 17:38:53 +04:00
|
|
|
|
2002-01-12 04:18:10 +03:00
|
|
|
if (height <= 0) {
|
|
|
|
nsIFrame* lastChild = GetLastFrame();
|
|
|
|
nsIFrame* startingPoint = mBottomFrame;
|
2012-07-30 18:20:58 +04:00
|
|
|
if (startingPoint == nullptr) {
|
2002-01-12 04:18:10 +03:00
|
|
|
// We just want to delete everything but the first item.
|
|
|
|
startingPoint = GetFirstFrame();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lastChild != startingPoint) {
|
|
|
|
// We have some hangers on (probably caused by shrinking the size of the window).
|
|
|
|
// Nuke them.
|
2003-08-04 16:39:51 +04:00
|
|
|
nsIFrame* currFrame = startingPoint->GetNextSibling();
|
2007-03-31 01:11:41 +04:00
|
|
|
nsBoxLayoutState state(PresContext());
|
2002-01-12 04:18:10 +03:00
|
|
|
|
2007-10-09 06:34:58 +04:00
|
|
|
nsCSSFrameConstructor* fc =
|
|
|
|
PresContext()->PresShell()->FrameConstructor();
|
|
|
|
fc->BeginUpdate();
|
2002-01-12 04:18:10 +03:00
|
|
|
while (currFrame) {
|
2003-08-04 16:39:51 +04:00
|
|
|
nsIFrame* nextFrame = currFrame->GetNextSibling();
|
2004-09-28 22:37:50 +04:00
|
|
|
RemoveChildFrame(state, currFrame);
|
2002-01-12 04:18:10 +03:00
|
|
|
currFrame = nextFrame;
|
|
|
|
}
|
2007-10-09 06:34:58 +04:00
|
|
|
fc->EndUpdate();
|
2002-01-12 04:18:10 +03:00
|
|
|
|
2007-03-31 01:11:41 +04:00
|
|
|
PresContext()->PresShell()->
|
2007-05-06 23:16:51 +04:00
|
|
|
FrameNeedsReflow(this, nsIPresShell::eTreeChange,
|
|
|
|
NS_FRAME_HAS_DIRTY_CHILDREN);
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
else
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2009-07-30 21:23:32 +04:00
|
|
|
nsListBoxBodyFrame::ListBoxAppendFrames(nsFrameList& aFrameList)
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
|
|
|
// append them after
|
2007-03-31 01:11:41 +04:00
|
|
|
nsBoxLayoutState state(PresContext());
|
2012-07-30 18:20:58 +04:00
|
|
|
const nsFrameList::Slice& newFrames = mFrames.AppendFrames(nullptr, aFrameList);
|
2004-09-28 22:37:50 +04:00
|
|
|
if (mLayoutManager)
|
2009-07-30 21:23:32 +04:00
|
|
|
mLayoutManager->ChildrenAppended(this, state, newFrames);
|
2007-03-31 01:11:41 +04:00
|
|
|
PresContext()->PresShell()->
|
2007-05-06 23:16:51 +04:00
|
|
|
FrameNeedsReflow(this, nsIPresShell::eTreeChange,
|
|
|
|
NS_FRAME_HAS_DIRTY_CHILDREN);
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2009-07-30 21:23:32 +04:00
|
|
|
nsListBoxBodyFrame::ListBoxInsertFrames(nsIFrame* aPrevFrame,
|
|
|
|
nsFrameList& aFrameList)
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
|
|
|
// insert the frames to our info list
|
2007-03-31 01:11:41 +04:00
|
|
|
nsBoxLayoutState state(PresContext());
|
2009-07-30 21:23:32 +04:00
|
|
|
const nsFrameList::Slice& newFrames =
|
2012-07-30 18:20:58 +04:00
|
|
|
mFrames.InsertFrames(nullptr, aPrevFrame, aFrameList);
|
2004-09-28 22:37:50 +04:00
|
|
|
if (mLayoutManager)
|
2009-07-30 21:23:32 +04:00
|
|
|
mLayoutManager->ChildrenInserted(this, state, aPrevFrame, newFrames);
|
2007-03-31 01:11:41 +04:00
|
|
|
PresContext()->PresShell()->
|
2007-05-06 23:16:51 +04:00
|
|
|
FrameNeedsReflow(this, nsIPresShell::eTreeChange,
|
|
|
|
NS_FRAME_HAS_DIRTY_CHILDREN);
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Called by nsCSSFrameConstructor when a new listitem content is inserted.
|
|
|
|
//
|
2015-12-07 04:15:53 +03:00
|
|
|
void
|
|
|
|
nsListBoxBodyFrame::OnContentInserted(nsIContent* aChildContent)
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
2004-04-21 21:06:27 +04:00
|
|
|
if (mRowCount >= 0)
|
|
|
|
++mRowCount;
|
2002-01-12 04:18:10 +03:00
|
|
|
|
2002-02-20 05:19:08 +03:00
|
|
|
// The RDF content builder will build content nodes such that they are all
|
|
|
|
// ready when OnContentInserted is first called, meaning the first call
|
|
|
|
// to CreateRows will create all the frames, but OnContentInserted will
|
|
|
|
// still be called again for each content node - so we need to make sure
|
|
|
|
// that the frame for each content node hasn't already been created.
|
2009-12-25 00:20:06 +03:00
|
|
|
nsIFrame* childFrame = aChildContent->GetPrimaryFrame();
|
2002-02-20 05:19:08 +03:00
|
|
|
if (childFrame)
|
|
|
|
return;
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t siblingIndex;
|
2002-01-12 04:18:10 +03:00
|
|
|
nsCOMPtr<nsIContent> nextSiblingContent;
|
|
|
|
GetListItemNextSibling(aChildContent, getter_AddRefs(nextSiblingContent), siblingIndex);
|
|
|
|
|
|
|
|
// if we're inserting our item before the first visible content,
|
|
|
|
// then we need to shift all rows down by one
|
|
|
|
if (siblingIndex >= 0 && siblingIndex-1 <= mCurrentIndex) {
|
2012-07-30 18:20:58 +04:00
|
|
|
mTopFrame = nullptr;
|
2002-01-12 04:18:10 +03:00
|
|
|
mRowsToPrepend = 1;
|
|
|
|
} else if (nextSiblingContent) {
|
|
|
|
// we may be inserting before a frame that is on screen
|
2009-12-25 00:20:06 +03:00
|
|
|
nsIFrame* nextSiblingFrame = nextSiblingContent->GetPrimaryFrame();
|
2002-01-12 04:18:10 +03:00
|
|
|
mLinkupFrame = nextSiblingFrame;
|
|
|
|
}
|
|
|
|
|
2005-02-05 06:32:17 +03:00
|
|
|
CreateRows();
|
2007-03-31 01:11:41 +04:00
|
|
|
PresContext()->PresShell()->
|
2007-05-06 23:16:51 +04:00
|
|
|
FrameNeedsReflow(this, nsIPresShell::eTreeChange,
|
|
|
|
NS_FRAME_HAS_DIRTY_CHILDREN);
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Called by nsCSSFrameConstructor when listitem content is removed.
|
|
|
|
//
|
|
|
|
void
|
2009-08-13 19:38:22 +04:00
|
|
|
nsListBoxBodyFrame::OnContentRemoved(nsPresContext* aPresContext,
|
|
|
|
nsIContent* aContainer,
|
|
|
|
nsIFrame* aChildFrame,
|
2010-07-15 08:38:24 +04:00
|
|
|
nsIContent* aOldNextSibling)
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
2006-02-13 00:37:45 +03:00
|
|
|
NS_ASSERTION(!aChildFrame || aChildFrame->GetParent() == this,
|
|
|
|
"Removing frame that's not our child... Not good");
|
|
|
|
|
2004-04-21 21:06:27 +04:00
|
|
|
if (mRowCount >= 0)
|
|
|
|
--mRowCount;
|
2002-01-12 04:18:10 +03:00
|
|
|
|
2009-08-13 19:38:22 +04:00
|
|
|
if (aContainer) {
|
2006-11-06 01:54:41 +03:00
|
|
|
if (!aChildFrame) {
|
|
|
|
// The row we are removing is out of view, so we need to try to
|
|
|
|
// determine the index of its next sibling.
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t siblingIndex = -1;
|
2010-07-15 08:38:24 +04:00
|
|
|
if (aOldNextSibling) {
|
2006-11-06 01:54:41 +03:00
|
|
|
nsCOMPtr<nsIContent> nextSiblingContent;
|
2010-07-15 08:38:24 +04:00
|
|
|
GetListItemNextSibling(aOldNextSibling,
|
|
|
|
getter_AddRefs(nextSiblingContent),
|
|
|
|
siblingIndex);
|
2006-11-06 01:54:41 +03:00
|
|
|
}
|
2002-01-12 04:18:10 +03:00
|
|
|
|
2006-11-06 01:54:41 +03:00
|
|
|
// if the row being removed is off-screen and above the top frame, we need to
|
|
|
|
// adjust our top index and tell the scrollbar to shift up one row.
|
|
|
|
if (siblingIndex >= 0 && siblingIndex-1 < mCurrentIndex) {
|
|
|
|
NS_PRECONDITION(mCurrentIndex > 0, "mCurrentIndex > 0");
|
2002-01-12 04:18:10 +03:00
|
|
|
--mCurrentIndex;
|
|
|
|
mYPosition = mCurrentIndex*mRowHeight;
|
2013-08-09 02:04:59 +04:00
|
|
|
nsWeakFrame weakChildFrame(aChildFrame);
|
2002-01-12 04:18:10 +03:00
|
|
|
VerticalScroll(mYPosition);
|
2013-08-09 02:04:59 +04:00
|
|
|
if (!weakChildFrame.IsAlive()) {
|
|
|
|
return;
|
|
|
|
}
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
2006-11-06 01:54:41 +03:00
|
|
|
} else if (mCurrentIndex > 0) {
|
|
|
|
// At this point, we know we have a scrollbar, and we need to know
|
|
|
|
// if we are scrolled to the last row. In this case, the behavior
|
|
|
|
// of the scrollbar is to stay locked to the bottom. Since we are
|
|
|
|
// removing visible content, the first visible row will have to move
|
|
|
|
// down by one, and we will have to insert a new frame at the top.
|
2013-05-02 02:50:08 +04:00
|
|
|
|
2006-11-06 01:54:41 +03:00
|
|
|
// if the last content node has a frame, we are scrolled to the bottom
|
2013-05-02 02:50:08 +04:00
|
|
|
nsIContent* lastChild = nullptr;
|
|
|
|
FlattenedChildIterator iter(mContent);
|
|
|
|
for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
|
|
|
|
lastChild = child;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lastChild) {
|
2009-12-25 00:20:06 +03:00
|
|
|
nsIFrame* lastChildFrame = lastChild->GetPrimaryFrame();
|
2013-05-02 02:50:08 +04:00
|
|
|
|
2006-11-06 01:54:41 +03:00
|
|
|
if (lastChildFrame) {
|
2012-07-30 18:20:58 +04:00
|
|
|
mTopFrame = nullptr;
|
2006-11-06 01:54:41 +03:00
|
|
|
mRowsToPrepend = 1;
|
|
|
|
--mCurrentIndex;
|
|
|
|
mYPosition = mCurrentIndex*mRowHeight;
|
2013-08-09 02:04:59 +04:00
|
|
|
nsWeakFrame weakChildFrame(aChildFrame);
|
2006-11-06 01:54:41 +03:00
|
|
|
VerticalScroll(mYPosition);
|
2013-08-09 02:04:59 +04:00
|
|
|
if (!weakChildFrame.IsAlive()) {
|
|
|
|
return;
|
|
|
|
}
|
2006-11-06 01:54:41 +03:00
|
|
|
}
|
|
|
|
}
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if we're removing the top row, the new top row is the next row
|
|
|
|
if (mTopFrame && mTopFrame == aChildFrame)
|
2003-08-04 16:39:51 +04:00
|
|
|
mTopFrame = mTopFrame->GetNextSibling();
|
2002-01-12 04:18:10 +03:00
|
|
|
|
|
|
|
// Go ahead and delete the frame.
|
|
|
|
nsBoxLayoutState state(aPresContext);
|
|
|
|
if (aChildFrame) {
|
2004-09-28 22:37:50 +04:00
|
|
|
RemoveChildFrame(state, aChildFrame);
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
2007-03-31 01:11:41 +04:00
|
|
|
PresContext()->PresShell()->
|
2007-05-06 23:16:51 +04:00
|
|
|
FrameNeedsReflow(this, nsIPresShell::eTreeChange,
|
|
|
|
NS_FRAME_HAS_DIRTY_CHILDREN);
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-08-22 19:56:38 +04:00
|
|
|
nsListBoxBodyFrame::GetListItemContentAt(int32_t aIndex, nsIContent** aContent)
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
2012-07-30 18:20:58 +04:00
|
|
|
*aContent = nullptr;
|
2002-01-12 04:18:10 +03:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t itemsFound = 0;
|
2013-05-02 02:50:08 +04:00
|
|
|
FlattenedChildIterator iter(mContent);
|
|
|
|
for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
|
2015-03-03 14:09:00 +03:00
|
|
|
if (child->IsXULElement(nsGkAtoms::listitem)) {
|
2002-01-12 04:18:10 +03:00
|
|
|
++itemsFound;
|
|
|
|
if (itemsFound-1 == aIndex) {
|
2013-05-02 02:50:08 +04:00
|
|
|
*aContent = child;
|
2002-01-12 04:18:10 +03:00
|
|
|
NS_IF_ADDREF(*aContent);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-08-22 19:56:38 +04:00
|
|
|
nsListBoxBodyFrame::GetListItemNextSibling(nsIContent* aListItem, nsIContent** aContent, int32_t& aSiblingIndex)
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
2012-07-30 18:20:58 +04:00
|
|
|
*aContent = nullptr;
|
2002-01-12 04:18:10 +03:00
|
|
|
aSiblingIndex = -1;
|
2012-07-30 18:20:58 +04:00
|
|
|
nsIContent *prevKid = nullptr;
|
2013-05-02 02:50:08 +04:00
|
|
|
FlattenedChildIterator iter(mContent);
|
|
|
|
for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
|
2015-03-03 14:09:00 +03:00
|
|
|
if (child->IsXULElement(nsGkAtoms::listitem)) {
|
2002-01-12 04:18:10 +03:00
|
|
|
++aSiblingIndex;
|
2003-09-27 08:18:26 +04:00
|
|
|
if (prevKid == aListItem) {
|
2013-05-02 02:50:08 +04:00
|
|
|
*aContent = child;
|
2002-01-12 04:18:10 +03:00
|
|
|
NS_IF_ADDREF(*aContent);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2013-05-02 02:50:08 +04:00
|
|
|
prevKid = child;
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
aSiblingIndex = -1; // no match, so there is no next sibling
|
|
|
|
}
|
|
|
|
|
2004-09-28 22:37:50 +04:00
|
|
|
void
|
|
|
|
nsListBoxBodyFrame::RemoveChildFrame(nsBoxLayoutState &aState,
|
|
|
|
nsIFrame *aFrame)
|
|
|
|
{
|
2013-03-24 00:10:33 +04:00
|
|
|
MOZ_ASSERT(mFrames.ContainsFrame(aFrame));
|
|
|
|
MOZ_ASSERT(aFrame != GetContentInsertionFrame());
|
2004-09-28 22:37:50 +04:00
|
|
|
|
2012-03-27 11:29:51 +04:00
|
|
|
#ifdef ACCESSIBILITY
|
|
|
|
nsAccessibilityService* accService = nsIPresShell::AccService();
|
|
|
|
if (accService) {
|
|
|
|
nsIContent* content = aFrame->GetContent();
|
2014-09-20 04:02:30 +04:00
|
|
|
accService->ContentRemoved(PresContext()->PresShell(), content);
|
2012-03-27 11:29:51 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-08-25 16:37:07 +04:00
|
|
|
mFrames.RemoveFrame(aFrame);
|
2004-09-28 22:37:50 +04:00
|
|
|
if (mLayoutManager)
|
|
|
|
mLayoutManager->ChildrenRemoved(this, aState, aFrame);
|
2006-04-10 04:16:29 +04:00
|
|
|
aFrame->Destroy();
|
2004-09-28 22:37:50 +04:00
|
|
|
}
|
|
|
|
|
2002-01-12 04:18:10 +03:00
|
|
|
// Creation Routines ///////////////////////////////////////////////////////////////////////
|
|
|
|
|
2011-07-11 18:05:10 +04:00
|
|
|
already_AddRefed<nsBoxLayout> NS_NewListBoxLayout();
|
2009-01-19 21:31:33 +03:00
|
|
|
|
2005-10-27 01:46:39 +04:00
|
|
|
nsIFrame*
|
2009-01-19 21:31:33 +03:00
|
|
|
NS_NewListBoxBodyFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
|
2002-01-12 04:18:10 +03:00
|
|
|
{
|
2011-07-11 18:05:10 +04:00
|
|
|
nsCOMPtr<nsBoxLayout> layout = NS_NewListBoxLayout();
|
2015-01-06 12:27:56 +03:00
|
|
|
return new (aPresShell) nsListBoxBodyFrame(aContext, layout);
|
2002-01-12 04:18:10 +03:00
|
|
|
}
|
2009-09-12 20:49:24 +04:00
|
|
|
|
|
|
|
NS_IMPL_FRAMEARENA_HELPERS(nsListBoxBodyFrame)
|