Fri, 16 Jan 2015 18:13:44 +0100
Integrate suggestion from review to improve consistency with existing code.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | // |
michael@0 | 7 | // Eric Vaughan |
michael@0 | 8 | // Netscape Communications |
michael@0 | 9 | // |
michael@0 | 10 | // See documentation in associated header file |
michael@0 | 11 | // |
michael@0 | 12 | |
michael@0 | 13 | #include "nsGridRowLeafLayout.h" |
michael@0 | 14 | #include "nsGridRowGroupLayout.h" |
michael@0 | 15 | #include "nsGridRow.h" |
michael@0 | 16 | #include "nsBoxLayoutState.h" |
michael@0 | 17 | #include "nsBox.h" |
michael@0 | 18 | #include "nsIScrollableFrame.h" |
michael@0 | 19 | #include "nsBoxFrame.h" |
michael@0 | 20 | #include "nsGridLayout2.h" |
michael@0 | 21 | #include <algorithm> |
michael@0 | 22 | |
michael@0 | 23 | already_AddRefed<nsBoxLayout> NS_NewGridRowLeafLayout() |
michael@0 | 24 | { |
michael@0 | 25 | nsRefPtr<nsBoxLayout> layout = new nsGridRowLeafLayout(); |
michael@0 | 26 | return layout.forget(); |
michael@0 | 27 | } |
michael@0 | 28 | |
michael@0 | 29 | nsGridRowLeafLayout::nsGridRowLeafLayout():nsGridRowLayout() |
michael@0 | 30 | { |
michael@0 | 31 | } |
michael@0 | 32 | |
michael@0 | 33 | nsGridRowLeafLayout::~nsGridRowLeafLayout() |
michael@0 | 34 | { |
michael@0 | 35 | } |
michael@0 | 36 | |
michael@0 | 37 | nsSize |
michael@0 | 38 | nsGridRowLeafLayout::GetPrefSize(nsIFrame* aBox, nsBoxLayoutState& aState) |
michael@0 | 39 | { |
michael@0 | 40 | int32_t index = 0; |
michael@0 | 41 | nsGrid* grid = GetGrid(aBox, &index); |
michael@0 | 42 | bool isHorizontal = IsHorizontal(aBox); |
michael@0 | 43 | |
michael@0 | 44 | // If we are not in a grid. Then we just work like a box. But if we are in a grid |
michael@0 | 45 | // ask the grid for our size. |
michael@0 | 46 | if (!grid) { |
michael@0 | 47 | return nsGridRowLayout::GetPrefSize(aBox, aState); |
michael@0 | 48 | } |
michael@0 | 49 | else { |
michael@0 | 50 | return grid->GetPrefRowSize(aState, index, isHorizontal); |
michael@0 | 51 | //AddBorderAndPadding(aBox, pref); |
michael@0 | 52 | } |
michael@0 | 53 | } |
michael@0 | 54 | |
michael@0 | 55 | nsSize |
michael@0 | 56 | nsGridRowLeafLayout::GetMinSize(nsIFrame* aBox, nsBoxLayoutState& aState) |
michael@0 | 57 | { |
michael@0 | 58 | int32_t index = 0; |
michael@0 | 59 | nsGrid* grid = GetGrid(aBox, &index); |
michael@0 | 60 | bool isHorizontal = IsHorizontal(aBox); |
michael@0 | 61 | |
michael@0 | 62 | if (!grid) |
michael@0 | 63 | return nsGridRowLayout::GetMinSize(aBox, aState); |
michael@0 | 64 | else { |
michael@0 | 65 | nsSize minSize = grid->GetMinRowSize(aState, index, isHorizontal); |
michael@0 | 66 | AddBorderAndPadding(aBox, minSize); |
michael@0 | 67 | return minSize; |
michael@0 | 68 | } |
michael@0 | 69 | } |
michael@0 | 70 | |
michael@0 | 71 | nsSize |
michael@0 | 72 | nsGridRowLeafLayout::GetMaxSize(nsIFrame* aBox, nsBoxLayoutState& aState) |
michael@0 | 73 | { |
michael@0 | 74 | int32_t index = 0; |
michael@0 | 75 | nsGrid* grid = GetGrid(aBox, &index); |
michael@0 | 76 | bool isHorizontal = IsHorizontal(aBox); |
michael@0 | 77 | |
michael@0 | 78 | if (!grid) |
michael@0 | 79 | return nsGridRowLayout::GetMaxSize(aBox, aState); |
michael@0 | 80 | else { |
michael@0 | 81 | nsSize maxSize; |
michael@0 | 82 | maxSize = grid->GetMaxRowSize(aState, index, isHorizontal); |
michael@0 | 83 | AddBorderAndPadding(aBox, maxSize); |
michael@0 | 84 | return maxSize; |
michael@0 | 85 | } |
michael@0 | 86 | } |
michael@0 | 87 | |
michael@0 | 88 | /** If a child is added or removed or changes size |
michael@0 | 89 | */ |
michael@0 | 90 | void |
michael@0 | 91 | nsGridRowLeafLayout::ChildAddedOrRemoved(nsIFrame* aBox, nsBoxLayoutState& aState) |
michael@0 | 92 | { |
michael@0 | 93 | int32_t index = 0; |
michael@0 | 94 | nsGrid* grid = GetGrid(aBox, &index); |
michael@0 | 95 | bool isHorizontal = IsHorizontal(aBox); |
michael@0 | 96 | |
michael@0 | 97 | if (grid) |
michael@0 | 98 | grid->CellAddedOrRemoved(aState, index, isHorizontal); |
michael@0 | 99 | } |
michael@0 | 100 | |
michael@0 | 101 | void |
michael@0 | 102 | nsGridRowLeafLayout::PopulateBoxSizes(nsIFrame* aBox, nsBoxLayoutState& aState, nsBoxSize*& aBoxSizes, nscoord& aMinSize, nscoord& aMaxSize, int32_t& aFlexes) |
michael@0 | 103 | { |
michael@0 | 104 | int32_t index = 0; |
michael@0 | 105 | nsGrid* grid = GetGrid(aBox, &index); |
michael@0 | 106 | bool isHorizontal = IsHorizontal(aBox); |
michael@0 | 107 | |
michael@0 | 108 | // Our base class SprocketLayout is giving us a chance to change the box sizes before layout |
michael@0 | 109 | // If we are a row lets change the sizes to match our columns. If we are a column then do the opposite |
michael@0 | 110 | // and make them match or rows. |
michael@0 | 111 | if (grid) { |
michael@0 | 112 | nsGridRow* column; |
michael@0 | 113 | int32_t count = grid->GetColumnCount(isHorizontal); |
michael@0 | 114 | nsBoxSize* start = nullptr; |
michael@0 | 115 | nsBoxSize* last = nullptr; |
michael@0 | 116 | nsBoxSize* current = nullptr; |
michael@0 | 117 | nsIFrame* child = aBox->GetChildBox(); |
michael@0 | 118 | for (int i=0; i < count; i++) |
michael@0 | 119 | { |
michael@0 | 120 | column = grid->GetColumnAt(i,isHorizontal); |
michael@0 | 121 | |
michael@0 | 122 | // make sure the value was computed before we use it. |
michael@0 | 123 | // !isHorizontal is passed in to invert the behavior of these methods. |
michael@0 | 124 | nscoord pref = |
michael@0 | 125 | grid->GetPrefRowHeight(aState, i, !isHorizontal); // GetPrefColumnWidth |
michael@0 | 126 | nscoord min = |
michael@0 | 127 | grid->GetMinRowHeight(aState, i, !isHorizontal); // GetMinColumnWidth |
michael@0 | 128 | nscoord max = |
michael@0 | 129 | grid->GetMaxRowHeight(aState, i, !isHorizontal); // GetMaxColumnWidth |
michael@0 | 130 | nscoord flex = |
michael@0 | 131 | grid->GetRowFlex(aState, i, !isHorizontal); // GetColumnFlex |
michael@0 | 132 | nscoord left = 0; |
michael@0 | 133 | nscoord right = 0; |
michael@0 | 134 | grid->GetRowOffsets(aState, i, left, right, !isHorizontal); // GetColumnOffsets |
michael@0 | 135 | nsIFrame* box = column->GetBox(); |
michael@0 | 136 | bool collapsed = false; |
michael@0 | 137 | nscoord topMargin = column->mTopMargin; |
michael@0 | 138 | nscoord bottomMargin = column->mBottomMargin; |
michael@0 | 139 | |
michael@0 | 140 | if (box) |
michael@0 | 141 | collapsed = box->IsCollapsed(); |
michael@0 | 142 | |
michael@0 | 143 | pref = pref - (left + right); |
michael@0 | 144 | if (pref < 0) |
michael@0 | 145 | pref = 0; |
michael@0 | 146 | |
michael@0 | 147 | // if this is the first or last column. Take into account that |
michael@0 | 148 | // our row could have a border that could affect our left or right |
michael@0 | 149 | // padding from our columns. If the row has padding subtract it. |
michael@0 | 150 | // would should always be able to garentee that our margin is smaller |
michael@0 | 151 | // or equal to our left or right |
michael@0 | 152 | int32_t firstIndex = 0; |
michael@0 | 153 | int32_t lastIndex = 0; |
michael@0 | 154 | nsGridRow* firstRow = nullptr; |
michael@0 | 155 | nsGridRow* lastRow = nullptr; |
michael@0 | 156 | grid->GetFirstAndLastRow(aState, firstIndex, lastIndex, firstRow, lastRow, !isHorizontal); |
michael@0 | 157 | |
michael@0 | 158 | if (i == firstIndex || i == lastIndex) { |
michael@0 | 159 | nsMargin offset = GetTotalMargin(aBox, isHorizontal); |
michael@0 | 160 | |
michael@0 | 161 | nsMargin border(0,0,0,0); |
michael@0 | 162 | // can't call GetBorderPadding we will get into recursion |
michael@0 | 163 | aBox->GetBorder(border); |
michael@0 | 164 | offset += border; |
michael@0 | 165 | aBox->GetPadding(border); |
michael@0 | 166 | offset += border; |
michael@0 | 167 | |
michael@0 | 168 | // subtract from out left and right |
michael@0 | 169 | if (i == firstIndex) |
michael@0 | 170 | { |
michael@0 | 171 | if (isHorizontal) |
michael@0 | 172 | left -= offset.left; |
michael@0 | 173 | else |
michael@0 | 174 | left -= offset.top; |
michael@0 | 175 | } |
michael@0 | 176 | |
michael@0 | 177 | if (i == lastIndex) |
michael@0 | 178 | { |
michael@0 | 179 | if (isHorizontal) |
michael@0 | 180 | right -= offset.right; |
michael@0 | 181 | else |
michael@0 | 182 | right -= offset.bottom; |
michael@0 | 183 | } |
michael@0 | 184 | } |
michael@0 | 185 | |
michael@0 | 186 | // initialize the box size here |
michael@0 | 187 | max = std::max(min, max); |
michael@0 | 188 | pref = nsBox::BoundsCheck(min, pref, max); |
michael@0 | 189 | |
michael@0 | 190 | current = new (aState) nsBoxSize(); |
michael@0 | 191 | current->pref = pref; |
michael@0 | 192 | current->min = min; |
michael@0 | 193 | current->max = max; |
michael@0 | 194 | current->flex = flex; |
michael@0 | 195 | current->bogus = column->mIsBogus; |
michael@0 | 196 | current->left = left + topMargin; |
michael@0 | 197 | current->right = right + bottomMargin; |
michael@0 | 198 | current->collapsed = collapsed; |
michael@0 | 199 | |
michael@0 | 200 | if (!start) { |
michael@0 | 201 | start = current; |
michael@0 | 202 | last = start; |
michael@0 | 203 | } else { |
michael@0 | 204 | last->next = current; |
michael@0 | 205 | last = current; |
michael@0 | 206 | } |
michael@0 | 207 | |
michael@0 | 208 | if (child && !column->mIsBogus) |
michael@0 | 209 | child = child->GetNextBox(); |
michael@0 | 210 | |
michael@0 | 211 | } |
michael@0 | 212 | aBoxSizes = start; |
michael@0 | 213 | } |
michael@0 | 214 | |
michael@0 | 215 | nsSprocketLayout::PopulateBoxSizes(aBox, aState, aBoxSizes, aMinSize, aMaxSize, aFlexes); |
michael@0 | 216 | } |
michael@0 | 217 | |
michael@0 | 218 | void |
michael@0 | 219 | nsGridRowLeafLayout::ComputeChildSizes(nsIFrame* aBox, |
michael@0 | 220 | nsBoxLayoutState& aState, |
michael@0 | 221 | nscoord& aGivenSize, |
michael@0 | 222 | nsBoxSize* aBoxSizes, |
michael@0 | 223 | nsComputedBoxSize*& aComputedBoxSizes) |
michael@0 | 224 | { |
michael@0 | 225 | // see if we are in a scrollable frame. If we are then there could be scrollbars present |
michael@0 | 226 | // if so we need to subtract them out to make sure our columns line up. |
michael@0 | 227 | if (aBox) { |
michael@0 | 228 | bool isHorizontal = aBox->IsHorizontal(); |
michael@0 | 229 | |
michael@0 | 230 | // go up the parent chain looking for scrollframes |
michael@0 | 231 | nscoord diff = 0; |
michael@0 | 232 | nsIFrame* parentBox; |
michael@0 | 233 | (void)GetParentGridPart(aBox, &parentBox); |
michael@0 | 234 | while (parentBox) { |
michael@0 | 235 | nsIFrame* scrollbox = nsGrid::GetScrollBox(parentBox); |
michael@0 | 236 | nsIScrollableFrame *scrollable = do_QueryFrame(scrollbox); |
michael@0 | 237 | if (scrollable) { |
michael@0 | 238 | // Don't call GetActualScrollbarSizes here because it's not safe |
michael@0 | 239 | // to call that while we're reflowing the contents of the scrollframe, |
michael@0 | 240 | // which we are here. |
michael@0 | 241 | nsMargin scrollbarSizes = scrollable->GetDesiredScrollbarSizes(&aState); |
michael@0 | 242 | uint32_t visible = scrollable->GetScrollbarVisibility(); |
michael@0 | 243 | |
michael@0 | 244 | if (isHorizontal && (visible & nsIScrollableFrame::VERTICAL)) { |
michael@0 | 245 | diff += scrollbarSizes.left + scrollbarSizes.right; |
michael@0 | 246 | } else if (!isHorizontal && (visible & nsIScrollableFrame::HORIZONTAL)) { |
michael@0 | 247 | diff += scrollbarSizes.top + scrollbarSizes.bottom; |
michael@0 | 248 | } |
michael@0 | 249 | } |
michael@0 | 250 | |
michael@0 | 251 | (void)GetParentGridPart(parentBox, &parentBox); |
michael@0 | 252 | } |
michael@0 | 253 | |
michael@0 | 254 | if (diff > 0) { |
michael@0 | 255 | aGivenSize += diff; |
michael@0 | 256 | |
michael@0 | 257 | nsSprocketLayout::ComputeChildSizes(aBox, aState, aGivenSize, aBoxSizes, aComputedBoxSizes); |
michael@0 | 258 | |
michael@0 | 259 | aGivenSize -= diff; |
michael@0 | 260 | |
michael@0 | 261 | nsComputedBoxSize* s = aComputedBoxSizes; |
michael@0 | 262 | nsComputedBoxSize* last = aComputedBoxSizes; |
michael@0 | 263 | while(s) |
michael@0 | 264 | { |
michael@0 | 265 | last = s; |
michael@0 | 266 | s = s->next; |
michael@0 | 267 | } |
michael@0 | 268 | |
michael@0 | 269 | if (last) |
michael@0 | 270 | last->size -= diff; |
michael@0 | 271 | |
michael@0 | 272 | return; |
michael@0 | 273 | } |
michael@0 | 274 | } |
michael@0 | 275 | |
michael@0 | 276 | nsSprocketLayout::ComputeChildSizes(aBox, aState, aGivenSize, aBoxSizes, aComputedBoxSizes); |
michael@0 | 277 | |
michael@0 | 278 | } |
michael@0 | 279 | |
michael@0 | 280 | NS_IMETHODIMP |
michael@0 | 281 | nsGridRowLeafLayout::Layout(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState) |
michael@0 | 282 | { |
michael@0 | 283 | return nsGridRowLayout::Layout(aBox, aBoxLayoutState); |
michael@0 | 284 | } |
michael@0 | 285 | |
michael@0 | 286 | void |
michael@0 | 287 | nsGridRowLeafLayout::DirtyRows(nsIFrame* aBox, nsBoxLayoutState& aState) |
michael@0 | 288 | { |
michael@0 | 289 | if (aBox) { |
michael@0 | 290 | // mark us dirty |
michael@0 | 291 | // XXXldb We probably don't want to walk up the ancestor chain |
michael@0 | 292 | // calling MarkIntrinsicWidthsDirty for every row. |
michael@0 | 293 | aState.PresShell()->FrameNeedsReflow(aBox, nsIPresShell::eTreeChange, |
michael@0 | 294 | NS_FRAME_IS_DIRTY); |
michael@0 | 295 | } |
michael@0 | 296 | } |
michael@0 | 297 | |
michael@0 | 298 | void |
michael@0 | 299 | nsGridRowLeafLayout::CountRowsColumns(nsIFrame* aBox, int32_t& aRowCount, int32_t& aComputedColumnCount) |
michael@0 | 300 | { |
michael@0 | 301 | if (aBox) { |
michael@0 | 302 | nsIFrame* child = aBox->GetChildBox(); |
michael@0 | 303 | |
michael@0 | 304 | // count the children |
michael@0 | 305 | int32_t columnCount = 0; |
michael@0 | 306 | while(child) { |
michael@0 | 307 | child = child->GetNextBox(); |
michael@0 | 308 | columnCount++; |
michael@0 | 309 | } |
michael@0 | 310 | |
michael@0 | 311 | // if our count is greater than the current column count |
michael@0 | 312 | if (columnCount > aComputedColumnCount) |
michael@0 | 313 | aComputedColumnCount = columnCount; |
michael@0 | 314 | |
michael@0 | 315 | aRowCount++; |
michael@0 | 316 | } |
michael@0 | 317 | } |
michael@0 | 318 | |
michael@0 | 319 | int32_t |
michael@0 | 320 | nsGridRowLeafLayout::BuildRows(nsIFrame* aBox, nsGridRow* aRows) |
michael@0 | 321 | { |
michael@0 | 322 | if (aBox) { |
michael@0 | 323 | aRows[0].Init(aBox, false); |
michael@0 | 324 | return 1; |
michael@0 | 325 | } |
michael@0 | 326 | |
michael@0 | 327 | return 0; |
michael@0 | 328 | } |
michael@0 | 329 |