1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/xul/grid/nsGridRowLeafLayout.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,329 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +// 1.10 +// Eric Vaughan 1.11 +// Netscape Communications 1.12 +// 1.13 +// See documentation in associated header file 1.14 +// 1.15 + 1.16 +#include "nsGridRowLeafLayout.h" 1.17 +#include "nsGridRowGroupLayout.h" 1.18 +#include "nsGridRow.h" 1.19 +#include "nsBoxLayoutState.h" 1.20 +#include "nsBox.h" 1.21 +#include "nsIScrollableFrame.h" 1.22 +#include "nsBoxFrame.h" 1.23 +#include "nsGridLayout2.h" 1.24 +#include <algorithm> 1.25 + 1.26 +already_AddRefed<nsBoxLayout> NS_NewGridRowLeafLayout() 1.27 +{ 1.28 + nsRefPtr<nsBoxLayout> layout = new nsGridRowLeafLayout(); 1.29 + return layout.forget(); 1.30 +} 1.31 + 1.32 +nsGridRowLeafLayout::nsGridRowLeafLayout():nsGridRowLayout() 1.33 +{ 1.34 +} 1.35 + 1.36 +nsGridRowLeafLayout::~nsGridRowLeafLayout() 1.37 +{ 1.38 +} 1.39 + 1.40 +nsSize 1.41 +nsGridRowLeafLayout::GetPrefSize(nsIFrame* aBox, nsBoxLayoutState& aState) 1.42 +{ 1.43 + int32_t index = 0; 1.44 + nsGrid* grid = GetGrid(aBox, &index); 1.45 + bool isHorizontal = IsHorizontal(aBox); 1.46 + 1.47 + // If we are not in a grid. Then we just work like a box. But if we are in a grid 1.48 + // ask the grid for our size. 1.49 + if (!grid) { 1.50 + return nsGridRowLayout::GetPrefSize(aBox, aState); 1.51 + } 1.52 + else { 1.53 + return grid->GetPrefRowSize(aState, index, isHorizontal); 1.54 + //AddBorderAndPadding(aBox, pref); 1.55 + } 1.56 +} 1.57 + 1.58 +nsSize 1.59 +nsGridRowLeafLayout::GetMinSize(nsIFrame* aBox, nsBoxLayoutState& aState) 1.60 +{ 1.61 + int32_t index = 0; 1.62 + nsGrid* grid = GetGrid(aBox, &index); 1.63 + bool isHorizontal = IsHorizontal(aBox); 1.64 + 1.65 + if (!grid) 1.66 + return nsGridRowLayout::GetMinSize(aBox, aState); 1.67 + else { 1.68 + nsSize minSize = grid->GetMinRowSize(aState, index, isHorizontal); 1.69 + AddBorderAndPadding(aBox, minSize); 1.70 + return minSize; 1.71 + } 1.72 +} 1.73 + 1.74 +nsSize 1.75 +nsGridRowLeafLayout::GetMaxSize(nsIFrame* aBox, nsBoxLayoutState& aState) 1.76 +{ 1.77 + int32_t index = 0; 1.78 + nsGrid* grid = GetGrid(aBox, &index); 1.79 + bool isHorizontal = IsHorizontal(aBox); 1.80 + 1.81 + if (!grid) 1.82 + return nsGridRowLayout::GetMaxSize(aBox, aState); 1.83 + else { 1.84 + nsSize maxSize; 1.85 + maxSize = grid->GetMaxRowSize(aState, index, isHorizontal); 1.86 + AddBorderAndPadding(aBox, maxSize); 1.87 + return maxSize; 1.88 + } 1.89 +} 1.90 + 1.91 +/** If a child is added or removed or changes size 1.92 + */ 1.93 +void 1.94 +nsGridRowLeafLayout::ChildAddedOrRemoved(nsIFrame* aBox, nsBoxLayoutState& aState) 1.95 +{ 1.96 + int32_t index = 0; 1.97 + nsGrid* grid = GetGrid(aBox, &index); 1.98 + bool isHorizontal = IsHorizontal(aBox); 1.99 + 1.100 + if (grid) 1.101 + grid->CellAddedOrRemoved(aState, index, isHorizontal); 1.102 +} 1.103 + 1.104 +void 1.105 +nsGridRowLeafLayout::PopulateBoxSizes(nsIFrame* aBox, nsBoxLayoutState& aState, nsBoxSize*& aBoxSizes, nscoord& aMinSize, nscoord& aMaxSize, int32_t& aFlexes) 1.106 +{ 1.107 + int32_t index = 0; 1.108 + nsGrid* grid = GetGrid(aBox, &index); 1.109 + bool isHorizontal = IsHorizontal(aBox); 1.110 + 1.111 + // Our base class SprocketLayout is giving us a chance to change the box sizes before layout 1.112 + // If we are a row lets change the sizes to match our columns. If we are a column then do the opposite 1.113 + // and make them match or rows. 1.114 + if (grid) { 1.115 + nsGridRow* column; 1.116 + int32_t count = grid->GetColumnCount(isHorizontal); 1.117 + nsBoxSize* start = nullptr; 1.118 + nsBoxSize* last = nullptr; 1.119 + nsBoxSize* current = nullptr; 1.120 + nsIFrame* child = aBox->GetChildBox(); 1.121 + for (int i=0; i < count; i++) 1.122 + { 1.123 + column = grid->GetColumnAt(i,isHorizontal); 1.124 + 1.125 + // make sure the value was computed before we use it. 1.126 + // !isHorizontal is passed in to invert the behavior of these methods. 1.127 + nscoord pref = 1.128 + grid->GetPrefRowHeight(aState, i, !isHorizontal); // GetPrefColumnWidth 1.129 + nscoord min = 1.130 + grid->GetMinRowHeight(aState, i, !isHorizontal); // GetMinColumnWidth 1.131 + nscoord max = 1.132 + grid->GetMaxRowHeight(aState, i, !isHorizontal); // GetMaxColumnWidth 1.133 + nscoord flex = 1.134 + grid->GetRowFlex(aState, i, !isHorizontal); // GetColumnFlex 1.135 + nscoord left = 0; 1.136 + nscoord right = 0; 1.137 + grid->GetRowOffsets(aState, i, left, right, !isHorizontal); // GetColumnOffsets 1.138 + nsIFrame* box = column->GetBox(); 1.139 + bool collapsed = false; 1.140 + nscoord topMargin = column->mTopMargin; 1.141 + nscoord bottomMargin = column->mBottomMargin; 1.142 + 1.143 + if (box) 1.144 + collapsed = box->IsCollapsed(); 1.145 + 1.146 + pref = pref - (left + right); 1.147 + if (pref < 0) 1.148 + pref = 0; 1.149 + 1.150 + // if this is the first or last column. Take into account that 1.151 + // our row could have a border that could affect our left or right 1.152 + // padding from our columns. If the row has padding subtract it. 1.153 + // would should always be able to garentee that our margin is smaller 1.154 + // or equal to our left or right 1.155 + int32_t firstIndex = 0; 1.156 + int32_t lastIndex = 0; 1.157 + nsGridRow* firstRow = nullptr; 1.158 + nsGridRow* lastRow = nullptr; 1.159 + grid->GetFirstAndLastRow(aState, firstIndex, lastIndex, firstRow, lastRow, !isHorizontal); 1.160 + 1.161 + if (i == firstIndex || i == lastIndex) { 1.162 + nsMargin offset = GetTotalMargin(aBox, isHorizontal); 1.163 + 1.164 + nsMargin border(0,0,0,0); 1.165 + // can't call GetBorderPadding we will get into recursion 1.166 + aBox->GetBorder(border); 1.167 + offset += border; 1.168 + aBox->GetPadding(border); 1.169 + offset += border; 1.170 + 1.171 + // subtract from out left and right 1.172 + if (i == firstIndex) 1.173 + { 1.174 + if (isHorizontal) 1.175 + left -= offset.left; 1.176 + else 1.177 + left -= offset.top; 1.178 + } 1.179 + 1.180 + if (i == lastIndex) 1.181 + { 1.182 + if (isHorizontal) 1.183 + right -= offset.right; 1.184 + else 1.185 + right -= offset.bottom; 1.186 + } 1.187 + } 1.188 + 1.189 + // initialize the box size here 1.190 + max = std::max(min, max); 1.191 + pref = nsBox::BoundsCheck(min, pref, max); 1.192 + 1.193 + current = new (aState) nsBoxSize(); 1.194 + current->pref = pref; 1.195 + current->min = min; 1.196 + current->max = max; 1.197 + current->flex = flex; 1.198 + current->bogus = column->mIsBogus; 1.199 + current->left = left + topMargin; 1.200 + current->right = right + bottomMargin; 1.201 + current->collapsed = collapsed; 1.202 + 1.203 + if (!start) { 1.204 + start = current; 1.205 + last = start; 1.206 + } else { 1.207 + last->next = current; 1.208 + last = current; 1.209 + } 1.210 + 1.211 + if (child && !column->mIsBogus) 1.212 + child = child->GetNextBox(); 1.213 + 1.214 + } 1.215 + aBoxSizes = start; 1.216 + } 1.217 + 1.218 + nsSprocketLayout::PopulateBoxSizes(aBox, aState, aBoxSizes, aMinSize, aMaxSize, aFlexes); 1.219 +} 1.220 + 1.221 +void 1.222 +nsGridRowLeafLayout::ComputeChildSizes(nsIFrame* aBox, 1.223 + nsBoxLayoutState& aState, 1.224 + nscoord& aGivenSize, 1.225 + nsBoxSize* aBoxSizes, 1.226 + nsComputedBoxSize*& aComputedBoxSizes) 1.227 +{ 1.228 + // see if we are in a scrollable frame. If we are then there could be scrollbars present 1.229 + // if so we need to subtract them out to make sure our columns line up. 1.230 + if (aBox) { 1.231 + bool isHorizontal = aBox->IsHorizontal(); 1.232 + 1.233 + // go up the parent chain looking for scrollframes 1.234 + nscoord diff = 0; 1.235 + nsIFrame* parentBox; 1.236 + (void)GetParentGridPart(aBox, &parentBox); 1.237 + while (parentBox) { 1.238 + nsIFrame* scrollbox = nsGrid::GetScrollBox(parentBox); 1.239 + nsIScrollableFrame *scrollable = do_QueryFrame(scrollbox); 1.240 + if (scrollable) { 1.241 + // Don't call GetActualScrollbarSizes here because it's not safe 1.242 + // to call that while we're reflowing the contents of the scrollframe, 1.243 + // which we are here. 1.244 + nsMargin scrollbarSizes = scrollable->GetDesiredScrollbarSizes(&aState); 1.245 + uint32_t visible = scrollable->GetScrollbarVisibility(); 1.246 + 1.247 + if (isHorizontal && (visible & nsIScrollableFrame::VERTICAL)) { 1.248 + diff += scrollbarSizes.left + scrollbarSizes.right; 1.249 + } else if (!isHorizontal && (visible & nsIScrollableFrame::HORIZONTAL)) { 1.250 + diff += scrollbarSizes.top + scrollbarSizes.bottom; 1.251 + } 1.252 + } 1.253 + 1.254 + (void)GetParentGridPart(parentBox, &parentBox); 1.255 + } 1.256 + 1.257 + if (diff > 0) { 1.258 + aGivenSize += diff; 1.259 + 1.260 + nsSprocketLayout::ComputeChildSizes(aBox, aState, aGivenSize, aBoxSizes, aComputedBoxSizes); 1.261 + 1.262 + aGivenSize -= diff; 1.263 + 1.264 + nsComputedBoxSize* s = aComputedBoxSizes; 1.265 + nsComputedBoxSize* last = aComputedBoxSizes; 1.266 + while(s) 1.267 + { 1.268 + last = s; 1.269 + s = s->next; 1.270 + } 1.271 + 1.272 + if (last) 1.273 + last->size -= diff; 1.274 + 1.275 + return; 1.276 + } 1.277 + } 1.278 + 1.279 + nsSprocketLayout::ComputeChildSizes(aBox, aState, aGivenSize, aBoxSizes, aComputedBoxSizes); 1.280 + 1.281 +} 1.282 + 1.283 +NS_IMETHODIMP 1.284 +nsGridRowLeafLayout::Layout(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState) 1.285 +{ 1.286 + return nsGridRowLayout::Layout(aBox, aBoxLayoutState); 1.287 +} 1.288 + 1.289 +void 1.290 +nsGridRowLeafLayout::DirtyRows(nsIFrame* aBox, nsBoxLayoutState& aState) 1.291 +{ 1.292 + if (aBox) { 1.293 + // mark us dirty 1.294 + // XXXldb We probably don't want to walk up the ancestor chain 1.295 + // calling MarkIntrinsicWidthsDirty for every row. 1.296 + aState.PresShell()->FrameNeedsReflow(aBox, nsIPresShell::eTreeChange, 1.297 + NS_FRAME_IS_DIRTY); 1.298 + } 1.299 +} 1.300 + 1.301 +void 1.302 +nsGridRowLeafLayout::CountRowsColumns(nsIFrame* aBox, int32_t& aRowCount, int32_t& aComputedColumnCount) 1.303 +{ 1.304 + if (aBox) { 1.305 + nsIFrame* child = aBox->GetChildBox(); 1.306 + 1.307 + // count the children 1.308 + int32_t columnCount = 0; 1.309 + while(child) { 1.310 + child = child->GetNextBox(); 1.311 + columnCount++; 1.312 + } 1.313 + 1.314 + // if our count is greater than the current column count 1.315 + if (columnCount > aComputedColumnCount) 1.316 + aComputedColumnCount = columnCount; 1.317 + 1.318 + aRowCount++; 1.319 + } 1.320 +} 1.321 + 1.322 +int32_t 1.323 +nsGridRowLeafLayout::BuildRows(nsIFrame* aBox, nsGridRow* aRows) 1.324 +{ 1.325 + if (aBox) { 1.326 + aRows[0].Init(aBox, false); 1.327 + return 1; 1.328 + } 1.329 + 1.330 + return 0; 1.331 +} 1.332 +