Bumping manifests a=b2g-bump
[gecko.git] / layout / xul / nsListBoxLayout.cpp
blob97939ef78e287c662a818ec66297e873d4a7b6f9
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsListBoxLayout.h"
8 #include "nsListBoxBodyFrame.h"
9 #include "nsBox.h"
10 #include "nsBoxLayoutState.h"
11 #include "nsIScrollableFrame.h"
12 #include "nsIReflowCallback.h"
13 #include "mozilla/dom/NameSpaceConstants.h"
14 #include "nsGkAtoms.h"
15 #include "nsContentUtils.h"
17 nsListBoxLayout::nsListBoxLayout() : nsGridRowGroupLayout()
21 ////////// nsBoxLayout //////////////
23 nsSize
24 nsListBoxLayout::GetPrefSize(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState)
26 nsSize pref = nsGridRowGroupLayout::GetPrefSize(aBox, aBoxLayoutState);
28 nsListBoxBodyFrame* frame = static_cast<nsListBoxBodyFrame*>(aBox);
29 if (frame) {
30 nscoord rowheight = frame->GetRowHeightAppUnits();
31 pref.height = frame->GetRowCount() * rowheight;
32 // Pad the height.
33 nscoord y = frame->GetAvailableHeight();
34 if (pref.height > y && y > 0 && rowheight > 0) {
35 nscoord m = (pref.height-y)%rowheight;
36 nscoord remainder = m == 0 ? 0 : rowheight - m;
37 pref.height += remainder;
39 if (nsContentUtils::HasNonEmptyAttr(frame->GetContent(), kNameSpaceID_None,
40 nsGkAtoms::sizemode)) {
41 nscoord width = frame->ComputeIntrinsicISize(aBoxLayoutState);
42 if (width > pref.width)
43 pref.width = width;
46 return pref;
49 nsSize
50 nsListBoxLayout::GetMinSize(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState)
52 nsSize minSize = nsGridRowGroupLayout::GetMinSize(aBox, aBoxLayoutState);
54 nsListBoxBodyFrame* frame = static_cast<nsListBoxBodyFrame*>(aBox);
55 if (frame) {
56 nscoord rowheight = frame->GetRowHeightAppUnits();
57 minSize.height = frame->GetRowCount() * rowheight;
58 // Pad the height.
59 nscoord y = frame->GetAvailableHeight();
60 if (minSize.height > y && y > 0 && rowheight > 0) {
61 nscoord m = (minSize.height-y)%rowheight;
62 nscoord remainder = m == 0 ? 0 : rowheight - m;
63 minSize.height += remainder;
65 if (nsContentUtils::HasNonEmptyAttr(frame->GetContent(), kNameSpaceID_None,
66 nsGkAtoms::sizemode)) {
67 nscoord width = frame->ComputeIntrinsicISize(aBoxLayoutState);
68 if (width > minSize.width)
69 minSize.width = width;
72 return minSize;
75 nsSize
76 nsListBoxLayout::GetMaxSize(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState)
78 nsSize maxSize = nsGridRowGroupLayout::GetMaxSize(aBox, aBoxLayoutState);
80 nsListBoxBodyFrame* frame = static_cast<nsListBoxBodyFrame*>(aBox);
81 if (frame) {
82 nscoord rowheight = frame->GetRowHeightAppUnits();
83 maxSize.height = frame->GetRowCount() * rowheight;
84 // Pad the height.
85 nscoord y = frame->GetAvailableHeight();
86 if (maxSize.height > y && y > 0 && rowheight > 0) {
87 nscoord m = (maxSize.height-y)%rowheight;
88 nscoord remainder = m == 0 ? 0 : rowheight - m;
89 maxSize.height += remainder;
92 return maxSize;
95 NS_IMETHODIMP
96 nsListBoxLayout::Layout(nsIFrame* aBox, nsBoxLayoutState& aState)
98 return LayoutInternal(aBox, aState);
102 /////////// nsListBoxLayout /////////////////////////
105 * Called to layout our our children. Does no frame construction
107 NS_IMETHODIMP
108 nsListBoxLayout::LayoutInternal(nsIFrame* aBox, nsBoxLayoutState& aState)
110 int32_t redrawStart = -1;
112 // Get the start y position.
113 nsListBoxBodyFrame* body = static_cast<nsListBoxBodyFrame*>(aBox);
114 if (!body) {
115 NS_ERROR("Frame encountered that isn't a listboxbody!");
116 return NS_ERROR_FAILURE;
119 nsMargin margin;
121 // Get our client rect.
122 nsRect clientRect;
123 aBox->GetClientRect(clientRect);
125 // Get the starting y position and the remaining available
126 // height.
127 nscoord availableHeight = body->GetAvailableHeight();
128 nscoord yOffset = body->GetYPosition();
130 if (availableHeight <= 0) {
131 bool fixed = (body->GetFixedRowSize() != -1);
132 if (fixed)
133 availableHeight = 10;
134 else
135 return NS_OK;
138 // run through all our currently created children
139 nsIFrame* box = nsBox::GetChildBox(body);
141 // if the reason is resize or initial we must relayout.
142 nscoord rowHeight = body->GetRowHeightAppUnits();
144 while (box) {
145 // If this box is dirty or if it has dirty children, we
146 // call layout on it.
147 nsRect childRect(box->GetRect());
148 box->GetMargin(margin);
150 // relayout if we must or we are dirty or some of our children are dirty
151 // or the client area is wider than us
152 // XXXldb There should probably be a resize check here too!
153 if (NS_SUBTREE_DIRTY(box) || childRect.width < clientRect.width) {
154 childRect.x = 0;
155 childRect.y = yOffset;
156 childRect.width = clientRect.width;
158 nsSize size = box->GetPrefSize(aState);
159 body->SetRowHeight(size.height);
161 childRect.height = rowHeight;
163 childRect.Deflate(margin);
164 box->SetBounds(aState, childRect);
165 box->Layout(aState);
166 } else {
167 // if the child did not need to be relayed out. Then its easy.
168 // Place the child by just grabbing its rect and adjusting the y.
169 int32_t newPos = yOffset+margin.top;
171 // are we pushing down or pulling up any rows?
172 // Then we may have to redraw everything below the moved
173 // rows.
174 if (redrawStart == -1 && childRect.y != newPos)
175 redrawStart = newPos;
177 childRect.y = newPos;
178 box->SetBounds(aState, childRect);
181 // Ok now the available size gets smaller and we move the
182 // starting position of the next child down some.
183 nscoord size = childRect.height + margin.top + margin.bottom;
185 yOffset += size;
186 availableHeight -= size;
188 box = nsBox::GetNextBox(box);
191 // We have enough available height left to add some more rows
192 // Since we can't do this during layout, we post a callback
193 // that will be processed after the reflow completes.
194 body->PostReflowCallback();
196 // if rows were pushed down or pulled up because some rows were added
197 // before them then redraw everything under the inserted rows. The inserted
198 // rows will automatically be redrawn because the were marked dirty on insertion.
199 if (redrawStart > -1) {
200 aBox->Redraw(aState);
203 return NS_OK;
206 // Creation Routines ///////////////////////////////////////////////////////////////////////
208 already_AddRefed<nsBoxLayout> NS_NewListBoxLayout()
210 nsRefPtr<nsBoxLayout> layout = new nsListBoxLayout();
211 return layout.forget();