2001-09-29 00:14:13 +04: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/. */
|
1999-09-03 18:25:15 +04:00
|
|
|
#include "nsSelectsAreaFrame.h"
|
|
|
|
#include "nsIContent.h"
|
2002-04-11 04:53:20 +04:00
|
|
|
#include "nsListControlFrame.h"
|
2006-01-26 05:29:17 +03:00
|
|
|
#include "nsDisplayList.h"
|
1999-09-03 18:25:15 +04:00
|
|
|
|
2005-11-04 05:38:33 +03:00
|
|
|
nsIFrame*
|
2012-08-22 19:56:38 +04:00
|
|
|
NS_NewSelectsAreaFrame(nsIPresShell* aShell, nsStyleContext* aContext, uint32_t aFlags)
|
1999-09-03 18:25:15 +04:00
|
|
|
{
|
2006-03-27 01:30:36 +04:00
|
|
|
nsSelectsAreaFrame* it = new (aShell) nsSelectsAreaFrame(aContext);
|
2005-11-04 05:38:33 +03:00
|
|
|
|
2013-08-03 08:11:06 +04:00
|
|
|
// We need NS_BLOCK_FLOAT_MGR to ensure that the options inside the select
|
|
|
|
// aren't expanded by right floats outside the select.
|
|
|
|
it->SetFlags(aFlags | NS_BLOCK_FLOAT_MGR);
|
2005-11-04 05:38:33 +03:00
|
|
|
|
|
|
|
return it;
|
1999-09-03 18:25:15 +04:00
|
|
|
}
|
|
|
|
|
2009-09-12 20:49:24 +04:00
|
|
|
NS_IMPL_FRAMEARENA_HELPERS(nsSelectsAreaFrame)
|
|
|
|
|
1999-09-03 18:25:15 +04:00
|
|
|
//---------------------------------------------------------
|
2006-01-26 05:29:17 +03:00
|
|
|
/**
|
|
|
|
* This wrapper class lets us redirect mouse hits from the child frame of
|
|
|
|
* an option element to the element's own frame.
|
|
|
|
* REVIEW: This is what nsSelectsAreaFrame::GetFrameForPoint used to do
|
|
|
|
*/
|
|
|
|
class nsDisplayOptionEventGrabber : public nsDisplayWrapList {
|
|
|
|
public:
|
2010-08-13 14:01:13 +04:00
|
|
|
nsDisplayOptionEventGrabber(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aFrame, nsDisplayItem* aItem)
|
|
|
|
: nsDisplayWrapList(aBuilder, aFrame, aItem) {}
|
|
|
|
nsDisplayOptionEventGrabber(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aFrame, nsDisplayList* aList)
|
|
|
|
: nsDisplayWrapList(aBuilder, aFrame, aList) {}
|
2010-04-08 04:31:26 +04:00
|
|
|
virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
|
|
|
|
HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames);
|
2010-07-16 01:07:49 +04:00
|
|
|
NS_DISPLAY_DECL_NAME("OptionEventGrabber", TYPE_OPTION_EVENT_GRABBER)
|
2006-01-26 05:29:17 +03:00
|
|
|
};
|
1999-09-03 18:25:15 +04:00
|
|
|
|
2010-04-08 04:31:26 +04:00
|
|
|
void nsDisplayOptionEventGrabber::HitTest(nsDisplayListBuilder* aBuilder,
|
|
|
|
const nsRect& aRect, HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
|
2006-01-26 05:29:17 +03:00
|
|
|
{
|
2010-04-08 04:31:26 +04:00
|
|
|
nsTArray<nsIFrame*> outFrames;
|
|
|
|
mList.HitTest(aBuilder, aRect, aState, &outFrames);
|
2000-03-22 05:43:08 +03:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
for (uint32_t i = 0; i < outFrames.Length(); i++) {
|
2010-04-08 04:31:26 +04:00
|
|
|
nsIFrame* selectedFrame = outFrames.ElementAt(i);
|
2006-01-26 05:29:17 +03:00
|
|
|
while (selectedFrame &&
|
2011-08-08 19:14:33 +04:00
|
|
|
!(selectedFrame->GetContent() &&
|
|
|
|
selectedFrame->GetContent()->IsHTML(nsGkAtoms::option))) {
|
2003-06-30 14:46:59 +04:00
|
|
|
selectedFrame = selectedFrame->GetParent();
|
2005-09-19 06:15:54 +04:00
|
|
|
}
|
2003-06-30 14:46:59 +04:00
|
|
|
if (selectedFrame) {
|
2010-04-08 04:31:26 +04:00
|
|
|
aOutFrames->AppendElement(selectedFrame);
|
|
|
|
} else {
|
|
|
|
// keep the original result, which could be this frame
|
|
|
|
aOutFrames->AppendElement(outFrames.ElementAt(i));
|
2000-03-22 05:43:08 +03:00
|
|
|
}
|
|
|
|
}
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
class nsOptionEventGrabberWrapper : public nsDisplayWrapper
|
2002-04-11 04:53:20 +04:00
|
|
|
{
|
2006-01-26 05:29:17 +03:00
|
|
|
public:
|
|
|
|
nsOptionEventGrabberWrapper() {}
|
|
|
|
virtual nsDisplayItem* WrapList(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aFrame, nsDisplayList* aList) {
|
2013-03-06 15:08:14 +04:00
|
|
|
return new (aBuilder) nsDisplayOptionEventGrabber(aBuilder, aFrame, aList);
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
virtual nsDisplayItem* WrapItem(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsDisplayItem* aItem) {
|
2013-04-19 16:02:13 +04:00
|
|
|
return new (aBuilder) nsDisplayOptionEventGrabber(aBuilder, aItem->Frame(), aItem);
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
};
|
2002-04-11 04:53:20 +04:00
|
|
|
|
2006-01-26 05:29:17 +03:00
|
|
|
static nsListControlFrame* GetEnclosingListFrame(nsIFrame* aSelectsAreaFrame)
|
|
|
|
{
|
|
|
|
nsIFrame* frame = aSelectsAreaFrame->GetParent();
|
2003-04-09 00:50:57 +04:00
|
|
|
while (frame) {
|
2006-12-26 20:47:52 +03:00
|
|
|
if (frame->GetType() == nsGkAtoms::listControlFrame)
|
2007-07-08 11:08:04 +04:00
|
|
|
return static_cast<nsListControlFrame*>(frame);
|
2003-06-30 14:46:59 +04:00
|
|
|
frame = frame->GetParent();
|
2003-04-09 00:50:57 +04:00
|
|
|
}
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
2006-04-18 06:41:42 +04:00
|
|
|
class nsDisplayListFocus : public nsDisplayItem {
|
|
|
|
public:
|
2010-08-13 14:01:13 +04:00
|
|
|
nsDisplayListFocus(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsSelectsAreaFrame* aFrame) :
|
|
|
|
nsDisplayItem(aBuilder, aFrame) {
|
2006-04-18 06:41:42 +04:00
|
|
|
MOZ_COUNT_CTOR(nsDisplayListFocus);
|
|
|
|
}
|
|
|
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
|
|
|
virtual ~nsDisplayListFocus() {
|
|
|
|
MOZ_COUNT_DTOR(nsDisplayListFocus);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-04-10 15:24:18 +04:00
|
|
|
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
|
|
|
|
*aSnap = false;
|
2006-04-18 06:41:42 +04:00
|
|
|
// override bounds because the list item focus ring may extend outside
|
|
|
|
// the nsSelectsAreaFrame
|
2013-04-19 16:02:13 +04:00
|
|
|
nsListControlFrame* listFrame = GetEnclosingListFrame(Frame());
|
2011-10-21 21:45:32 +04:00
|
|
|
return listFrame->GetVisualOverflowRectRelativeToSelf() +
|
2012-09-16 14:32:59 +04:00
|
|
|
listFrame->GetOffsetToCrossDoc(ReferenceFrame());
|
2006-04-18 06:41:42 +04:00
|
|
|
}
|
2009-09-07 04:35:14 +04:00
|
|
|
virtual void Paint(nsDisplayListBuilder* aBuilder,
|
2011-04-08 05:04:40 +04:00
|
|
|
nsRenderingContext* aCtx) {
|
2013-04-19 16:02:13 +04:00
|
|
|
nsListControlFrame* listFrame = GetEnclosingListFrame(Frame());
|
2006-04-18 06:41:42 +04:00
|
|
|
// listFrame must be non-null or we wouldn't get called.
|
|
|
|
listFrame->PaintFocus(*aCtx, aBuilder->ToReferenceFrame(listFrame));
|
|
|
|
}
|
2010-07-16 01:07:49 +04:00
|
|
|
NS_DISPLAY_DECL_NAME("ListFocus", TYPE_LIST_FOCUS)
|
2006-04-18 06:41:42 +04:00
|
|
|
};
|
2003-04-09 00:50:57 +04:00
|
|
|
|
2013-02-14 15:12:27 +04:00
|
|
|
void
|
2006-01-26 05:29:17 +03:00
|
|
|
nsSelectsAreaFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|
|
|
const nsRect& aDirtyRect,
|
|
|
|
const nsDisplayListSet& aLists)
|
|
|
|
{
|
2013-02-14 15:12:27 +04:00
|
|
|
if (!aBuilder->IsForEventDelivery()) {
|
|
|
|
BuildDisplayListInternal(aBuilder, aDirtyRect, aLists);
|
|
|
|
return;
|
|
|
|
}
|
2013-03-06 15:08:14 +04:00
|
|
|
|
2006-01-26 05:29:17 +03:00
|
|
|
nsDisplayListCollection set;
|
2013-02-14 15:12:27 +04:00
|
|
|
BuildDisplayListInternal(aBuilder, aDirtyRect, set);
|
2006-01-26 05:29:17 +03:00
|
|
|
|
|
|
|
nsOptionEventGrabberWrapper wrapper;
|
2013-02-14 15:12:27 +04:00
|
|
|
wrapper.WrapLists(aBuilder, this, set, aLists);
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
2013-02-14 15:12:27 +04:00
|
|
|
void
|
2006-01-26 05:29:17 +03:00
|
|
|
nsSelectsAreaFrame::BuildDisplayListInternal(nsDisplayListBuilder* aBuilder,
|
|
|
|
const nsRect& aDirtyRect,
|
|
|
|
const nsDisplayListSet& aLists)
|
|
|
|
{
|
2013-02-14 15:08:08 +04:00
|
|
|
nsBlockFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
|
2006-01-26 05:29:17 +03:00
|
|
|
|
|
|
|
nsListControlFrame* listFrame = GetEnclosingListFrame(this);
|
|
|
|
if (listFrame && listFrame->IsFocused()) {
|
|
|
|
// we can't just associate the display item with the list frame,
|
|
|
|
// because then the list's scrollframe won't clip it (the scrollframe
|
|
|
|
// only clips contained descendants).
|
2013-02-14 15:08:08 +04:00
|
|
|
aLists.Outlines()->AppendNewToTop(new (aBuilder)
|
2010-08-13 14:01:13 +04:00
|
|
|
nsDisplayListFocus(aBuilder, this));
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
2002-04-11 07:25:58 +04:00
|
|
|
}
|
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
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSelectsAreaFrame::Reflow(nsPresContext* aPresContext,
|
|
|
|
nsHTMLReflowMetrics& aDesiredSize,
|
|
|
|
const nsHTMLReflowState& aReflowState,
|
|
|
|
nsReflowStatus& aStatus)
|
|
|
|
{
|
|
|
|
nsListControlFrame* list = GetEnclosingListFrame(this);
|
|
|
|
NS_ASSERTION(list,
|
|
|
|
"Must have an nsListControlFrame! Frame constructor is "
|
|
|
|
"broken");
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool isInDropdownMode = list->IsInDropDownMode();
|
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
|
|
|
|
|
|
|
// See similar logic in nsListControlFrame::Reflow and
|
|
|
|
// nsListControlFrame::ReflowAsDropdown. We need to match it here.
|
|
|
|
nscoord oldHeight;
|
|
|
|
if (isInDropdownMode) {
|
|
|
|
// Store the height now in case it changes during
|
2008-12-29 18:07:38 +03:00
|
|
|
// nsBlockFrame::Reflow for some odd reason.
|
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
|
|
|
if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
|
|
|
|
oldHeight = GetSize().height;
|
|
|
|
} else {
|
|
|
|
oldHeight = NS_UNCONSTRAINEDSIZE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-29 18:07:38 +03:00
|
|
|
nsresult rv = nsBlockFrame::Reflow(aPresContext, aDesiredSize,
|
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
|
|
|
aReflowState, aStatus);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2012-12-21 12:38:49 +04:00
|
|
|
// Check whether we need to suppress scrollbar updates. We want to do that if
|
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
|
|
|
// we're in a possible first pass and our height of a row has changed.
|
|
|
|
if (list->MightNeedSecondPass()) {
|
2012-01-25 05:21:29 +04:00
|
|
|
nscoord newHeightOfARow = list->CalcHeightOfARow();
|
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
|
|
|
// We'll need a second pass if our height of a row changed. For
|
|
|
|
// comboboxes, we'll also need it if our height changed. If we're going
|
|
|
|
// to do a second pass, suppress scrollbar updates for this pass.
|
|
|
|
if (newHeightOfARow != mHeightOfARow ||
|
2013-12-27 21:59:52 +04:00
|
|
|
(isInDropdownMode && (oldHeight != aDesiredSize.Height() ||
|
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
|
|
|
oldHeight != GetSize().height))) {
|
|
|
|
mHeightOfARow = newHeightOfARow;
|
2011-10-17 18:59:28 +04:00
|
|
|
list->SetSuppressScrollbarUpdate(true);
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|