nsGridRowLeafLayout.cpp 9.4 KB

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