GridFormattingContext.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. /*
  2. * Copyright (c) 2022, Martin Falisse <mfalisse@outlook.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibWeb/DOM/Node.h>
  7. #include <LibWeb/Layout/Box.h>
  8. #include <LibWeb/Layout/GridFormattingContext.h>
  9. namespace Web::Layout {
  10. GridFormattingContext::GridFormattingContext(LayoutState& state, BlockContainer const& block_container, FormattingContext* parent)
  11. : BlockFormattingContext(state, block_container, parent)
  12. {
  13. }
  14. GridFormattingContext::~GridFormattingContext() = default;
  15. void GridFormattingContext::run(Box const& box, LayoutMode)
  16. {
  17. auto should_skip_is_anonymous_text_run = [&](Box& child_box) -> bool {
  18. if (child_box.is_anonymous() && !child_box.first_child_of_type<BlockContainer>()) {
  19. bool contains_only_white_space = true;
  20. child_box.for_each_in_subtree([&](auto const& node) {
  21. if (!is<TextNode>(node) || !static_cast<TextNode const&>(node).dom_node().data().is_whitespace()) {
  22. contains_only_white_space = false;
  23. return IterationDecision::Break;
  24. }
  25. return IterationDecision::Continue;
  26. });
  27. if (contains_only_white_space)
  28. return true;
  29. }
  30. return false;
  31. };
  32. auto maybe_add_column_to_occupation_grid = [](int needed_number_of_columns, Vector<Vector<bool>>& occupation_grid) -> void {
  33. int current_column_count = (int)occupation_grid[0].size();
  34. if (needed_number_of_columns <= current_column_count)
  35. return;
  36. for (auto& occupation_grid_row : occupation_grid)
  37. for (int idx = 0; idx < (needed_number_of_columns + 1) - current_column_count; idx++)
  38. occupation_grid_row.append(false);
  39. };
  40. auto maybe_add_row_to_occupation_grid = [](int needed_number_of_rows, Vector<Vector<bool>>& occupation_grid) -> void {
  41. if (needed_number_of_rows <= (int)occupation_grid.size())
  42. return;
  43. Vector<bool> new_occupation_grid_row;
  44. for (int idx = 0; idx < (int)occupation_grid[0].size(); idx++)
  45. new_occupation_grid_row.append(false);
  46. for (int idx = 0; idx < needed_number_of_rows - (int)occupation_grid.size(); idx++)
  47. occupation_grid.append(new_occupation_grid_row);
  48. };
  49. auto set_occupied_cells = [](int row_start, int row_end, int column_start, int column_end, Vector<Vector<bool>>& occupation_grid) -> void {
  50. for (int row_index = 0; row_index < (int)occupation_grid.size(); row_index++) {
  51. if (row_index >= row_start && row_index < row_end) {
  52. for (int column_index = 0; column_index < (int)occupation_grid[0].size(); column_index++) {
  53. if (column_index >= column_start && column_index < column_end) {
  54. occupation_grid[row_index][column_index] = true;
  55. }
  56. }
  57. }
  58. }
  59. };
  60. // https://drafts.csswg.org/css-grid/#overview-placement
  61. // 2.2. Placing Items
  62. // The contents of the grid container are organized into individual grid items (analogous to
  63. // flex items), which are then assigned to predefined areas in the grid. They can be explicitly
  64. // placed using coordinates through the grid-placement properties or implicitly placed into
  65. // empty areas using auto-placement.
  66. struct PositionedBox {
  67. Box const& box;
  68. int row { 0 };
  69. int row_span { 1 };
  70. int column { 0 };
  71. int column_span { 1 };
  72. float computed_height { 0 };
  73. };
  74. Vector<PositionedBox> positioned_boxes;
  75. Vector<Vector<bool>> occupation_grid;
  76. Vector<bool> occupation_grid_row;
  77. for (int column_index = 0; column_index < max((int)box.computed_values().grid_template_columns().size(), 1); column_index++)
  78. occupation_grid_row.append(false);
  79. for (int row_index = 0; row_index < max((int)box.computed_values().grid_template_rows().size(), 1); row_index++)
  80. occupation_grid.append(occupation_grid_row);
  81. Vector<Box const&> boxes_to_place;
  82. box.for_each_child_of_type<Box>([&](Box& child_box) {
  83. if (should_skip_is_anonymous_text_run(child_box))
  84. return IterationDecision::Continue;
  85. boxes_to_place.append(child_box);
  86. return IterationDecision::Continue;
  87. });
  88. // https://drafts.csswg.org/css-grid/#auto-placement-algo
  89. // 8.5. Grid Item Placement Algorithm
  90. // FIXME: 0. Generate anonymous grid items
  91. // 1. Position anything that's not auto-positioned.
  92. for (size_t i = 0; i < boxes_to_place.size(); i++) {
  93. auto const& child_box = boxes_to_place[i];
  94. if (child_box.computed_values().grid_row_start().is_auto()
  95. || child_box.computed_values().grid_row_end().is_auto()
  96. || child_box.computed_values().grid_column_start().is_auto()
  97. || child_box.computed_values().grid_column_end().is_auto())
  98. continue;
  99. int row_start = child_box.computed_values().grid_row_start().position();
  100. int row_end = child_box.computed_values().grid_row_end().position();
  101. int column_start = child_box.computed_values().grid_column_start().position();
  102. int column_end = child_box.computed_values().grid_column_end().position();
  103. int row_span = 1;
  104. int column_span = 1;
  105. // https://drafts.csswg.org/css-grid/#grid-placement-int
  106. // [ <integer [−∞,−1]> | <integer [1,∞]> ] && <custom-ident>?
  107. // Contributes the Nth grid line to the grid item’s placement. If a negative integer is given, it
  108. // instead counts in reverse, starting from the end edge of the explicit grid.
  109. if (row_end < 0)
  110. row_end = static_cast<int>(occupation_grid.size()) + row_end + 2;
  111. if (column_end < 0)
  112. column_end = static_cast<int>(occupation_grid[0].size()) + column_end + 2;
  113. // FIXME: If a name is given as a <custom-ident>, only lines with that name are counted. If not enough
  114. // lines with that name exist, all implicit grid lines are assumed to have that name for the purpose
  115. // of finding this position.
  116. // FIXME: An <integer> value of zero makes the declaration invalid.
  117. // https://drafts.csswg.org/css-grid/#grid-placement-errors
  118. // 8.3.1. Grid Placement Conflict Handling
  119. // If the placement for a grid item contains two lines, and the start line is further end-ward than
  120. // the end line, swap the two lines. If the start line is equal to the end line, remove the end
  121. // line.
  122. if (row_start > row_end) {
  123. auto temp = row_end;
  124. row_end = row_start;
  125. row_start = temp;
  126. }
  127. if (column_start > column_end) {
  128. auto temp = column_end;
  129. column_end = column_start;
  130. column_start = temp;
  131. }
  132. if (row_start != row_end)
  133. row_span = row_end - row_start;
  134. if (column_start != column_end)
  135. column_span = column_end - column_start;
  136. // FIXME: If the placement contains two spans, remove the one contributed by the end grid-placement
  137. // property.
  138. // FIXME: If the placement contains only a span for a named line, replace it with a span of 1.
  139. row_start -= 1;
  140. column_start -= 1;
  141. positioned_boxes.append({ child_box, row_start, row_span, column_start, column_span });
  142. maybe_add_row_to_occupation_grid(row_start + row_span, occupation_grid);
  143. maybe_add_column_to_occupation_grid(column_start + column_span, occupation_grid);
  144. set_occupied_cells(row_start, row_start + row_span, column_start, column_start + column_span, occupation_grid);
  145. boxes_to_place.remove(i);
  146. i--;
  147. }
  148. // 2. Process the items locked to a given row.
  149. // FIXME: Do "dense" packing
  150. for (size_t i = 0; i < boxes_to_place.size(); i++) {
  151. auto const& child_box = boxes_to_place[i];
  152. if (child_box.computed_values().grid_row_start().is_auto()
  153. || child_box.computed_values().grid_row_end().is_auto())
  154. continue;
  155. int row_start = child_box.computed_values().grid_row_start().position();
  156. int row_end = child_box.computed_values().grid_row_end().position();
  157. int row_span = 1;
  158. // https://drafts.csswg.org/css-grid/#grid-placement-int
  159. // [ <integer [−∞,−1]> | <integer [1,∞]> ] && <custom-ident>?
  160. // Contributes the Nth grid line to the grid item’s placement. If a negative integer is given, it
  161. // instead counts in reverse, starting from the end edge of the explicit grid.
  162. if (row_end < 0)
  163. row_end = static_cast<int>(occupation_grid.size()) + row_end + 2;
  164. // FIXME: If a name is given as a <custom-ident>, only lines with that name are counted. If not enough
  165. // lines with that name exist, all implicit grid lines are assumed to have that name for the purpose
  166. // of finding this position.
  167. // FIXME: An <integer> value of zero makes the declaration invalid.
  168. // https://drafts.csswg.org/css-grid/#grid-placement-errors
  169. // 8.3.1. Grid Placement Conflict Handling
  170. // If the placement for a grid item contains two lines, and the start line is further end-ward than
  171. // the end line, swap the two lines. If the start line is equal to the end line, remove the end
  172. // line.
  173. if (row_start > row_end) {
  174. auto temp = row_end;
  175. row_end = row_start;
  176. row_start = temp;
  177. }
  178. if (row_start != row_end)
  179. row_span = row_end - row_start;
  180. // FIXME: If the placement contains two spans, remove the one contributed by the end grid-placement
  181. // property.
  182. // FIXME: If the placement contains only a span for a named line, replace it with a span of 1.
  183. row_start -= 1;
  184. maybe_add_row_to_occupation_grid(row_start + row_span, occupation_grid);
  185. int column_start = 0;
  186. int column_span = 1;
  187. bool found_available_column = false;
  188. for (int column_index = column_start; column_index < (int)occupation_grid[0].size(); column_index++) {
  189. if (!occupation_grid[0][column_index]) {
  190. found_available_column = true;
  191. column_start = column_index;
  192. break;
  193. }
  194. }
  195. if (!found_available_column) {
  196. column_start = occupation_grid[0].size();
  197. maybe_add_column_to_occupation_grid(column_start + column_span, occupation_grid);
  198. }
  199. set_occupied_cells(row_start, row_start + row_span, column_start, column_start + column_span, occupation_grid);
  200. positioned_boxes.append({ child_box, row_start, row_span, column_start, column_span });
  201. boxes_to_place.remove(i);
  202. i--;
  203. }
  204. // 3. Determine the columns in the implicit grid.
  205. // NOTE: "implicit grid" here is the same as the occupation_grid
  206. // 3.1. Start with the columns from the explicit grid.
  207. // NOTE: Done in step 1.
  208. // 3.2. Among all the items with a definite column position (explicitly positioned items, items
  209. // positioned in the previous step, and items not yet positioned but with a definite column) add
  210. // columns to the beginning and end of the implicit grid as necessary to accommodate those items.
  211. // NOTE: "Explicitly positioned items" and "items positioned in the previous step" done in step 1
  212. // and 2, respectively. Adding columns for "items not yet positioned but with a definite column"
  213. // will be done in step 4.
  214. // 3.3. If the largest column span among all the items without a definite column position is larger
  215. // than the width of the implicit grid, add columns to the end of the implicit grid to accommodate
  216. // that column span.
  217. // NOTE: Done in step 1, 2, and will be done in step 4.
  218. // 4. Position the remaining grid items.
  219. // For each grid item that hasn't been positioned by the previous steps, in order-modified document
  220. // order:
  221. auto auto_placement_cursor_x = 0;
  222. auto auto_placement_cursor_y = 0;
  223. for (size_t i = 0; i < boxes_to_place.size(); i++) {
  224. auto const& child_box = boxes_to_place[i];
  225. // 4.1. For sparse packing:
  226. // FIXME: no distinction made. See #4.2
  227. // 4.1.1. If the item has a definite column position:
  228. if (!child_box.computed_values().grid_column_start().is_auto()) {
  229. int column_start = child_box.computed_values().grid_column_start().position();
  230. int column_end = child_box.computed_values().grid_column_end().position();
  231. int column_span = 1;
  232. // https://drafts.csswg.org/css-grid/#grid-placement-int
  233. // [ <integer [−∞,−1]> | <integer [1,∞]> ] && <custom-ident>?
  234. // Contributes the Nth grid line to the grid item’s placement. If a negative integer is given, it
  235. // instead counts in reverse, starting from the end edge of the explicit grid.
  236. if (column_end < 0)
  237. column_end = static_cast<int>(occupation_grid[0].size()) + column_end + 2;
  238. // FIXME: If a name is given as a <custom-ident>, only lines with that name are counted. If not enough
  239. // lines with that name exist, all implicit grid lines are assumed to have that name for the purpose
  240. // of finding this position.
  241. // FIXME: An <integer> value of zero makes the declaration invalid.
  242. // https://drafts.csswg.org/css-grid/#grid-placement-errors
  243. // 8.3.1. Grid Placement Conflict Handling
  244. // If the placement for a grid item contains two lines, and the start line is further end-ward than
  245. // the end line, swap the two lines. If the start line is equal to the end line, remove the end
  246. // line.
  247. if (!child_box.computed_values().grid_column_end().is_auto()) {
  248. if (column_start > column_end) {
  249. auto temp = column_end;
  250. column_end = column_start;
  251. column_start = temp;
  252. }
  253. if (column_start != column_end)
  254. column_span = column_end - column_start;
  255. }
  256. // FIXME: If the placement contains two spans, remove the one contributed by the end grid-placement
  257. // property.
  258. // FIXME: If the placement contains only a span for a named line, replace it with a span of 1.
  259. column_start -= 1;
  260. // 4.1.1.1. Set the column position of the cursor to the grid item's column-start line. If this is
  261. // less than the previous column position of the cursor, increment the row position by 1.
  262. auto_placement_cursor_x = column_start;
  263. if (column_start < auto_placement_cursor_x)
  264. auto_placement_cursor_y++;
  265. maybe_add_column_to_occupation_grid(auto_placement_cursor_x + 1, occupation_grid);
  266. maybe_add_row_to_occupation_grid(auto_placement_cursor_y + 1, occupation_grid);
  267. // 4.1.1.2. Increment the cursor's row position until a value is found where the grid item does not
  268. // overlap any occupied grid cells (creating new rows in the implicit grid as necessary).
  269. while (true) {
  270. if (!occupation_grid[auto_placement_cursor_y][column_start]) {
  271. break;
  272. }
  273. auto_placement_cursor_y++;
  274. maybe_add_row_to_occupation_grid(auto_placement_cursor_y + 1, occupation_grid);
  275. }
  276. // 4.1.1.3. Set the item's row-start line to the cursor's row position, and set the item's row-end
  277. // line according to its span from that position.
  278. set_occupied_cells(auto_placement_cursor_y, auto_placement_cursor_y + 1, column_start, column_start + column_span, occupation_grid);
  279. positioned_boxes.append({ child_box, auto_placement_cursor_y, 1, column_start, column_span });
  280. }
  281. // 4.1.2. If the item has an automatic grid position in both axes:
  282. else {
  283. // 4.1.2.1. Increment the column position of the auto-placement cursor until either this item's grid
  284. // area does not overlap any occupied grid cells, or the cursor's column position, plus the item's
  285. // column span, overflow the number of columns in the implicit grid, as determined earlier in this
  286. // algorithm.
  287. auto column_start = 0;
  288. auto column_span = 1;
  289. auto row_start = 0;
  290. auto row_span = 1;
  291. auto found_unoccupied_cell = false;
  292. for (int row_index = auto_placement_cursor_y; row_index < (int)occupation_grid.size(); row_index++) {
  293. for (int column_index = auto_placement_cursor_x; column_index < (int)occupation_grid[0].size(); column_index++) {
  294. if (!occupation_grid[row_index][column_index]) {
  295. found_unoccupied_cell = true;
  296. column_start = column_index;
  297. row_start = row_index;
  298. goto finish;
  299. }
  300. auto_placement_cursor_x = 0;
  301. }
  302. auto_placement_cursor_x = 0;
  303. auto_placement_cursor_y++;
  304. }
  305. finish:
  306. // 4.1.2.2. If a non-overlapping position was found in the previous step, set the item's row-start
  307. // and column-start lines to the cursor's position. Otherwise, increment the auto-placement cursor's
  308. // row position (creating new rows in the implicit grid as necessary), set its column position to the
  309. // start-most column line in the implicit grid, and return to the previous step.
  310. if (!found_unoccupied_cell) {
  311. row_start = (int)occupation_grid.size();
  312. maybe_add_row_to_occupation_grid((int)occupation_grid.size() + 1, occupation_grid);
  313. }
  314. set_occupied_cells(row_start, row_start + row_span, column_start, column_start + column_span, occupation_grid);
  315. positioned_boxes.append({ child_box, row_start, row_span, column_start, column_span });
  316. }
  317. boxes_to_place.remove(i);
  318. i--;
  319. // FIXME: 4.2. For dense packing:
  320. }
  321. // https://drafts.csswg.org/css-grid/#overview-sizing
  322. // 2.3. Sizing the Grid
  323. // Once the grid items have been placed, the sizes of the grid tracks (rows and columns) are
  324. // calculated, accounting for the sizes of their contents and/or available space as specified in
  325. // the grid definition.
  326. // https://drafts.csswg.org/css-grid/#layout-algorithm
  327. // 12. Grid Sizing
  328. // This section defines the grid sizing algorithm, which determines the size of all grid tracks and,
  329. // by extension, the entire grid.
  330. // Each track has specified minimum and maximum sizing functions (which may be the same). Each
  331. // sizing function is either:
  332. // - A fixed sizing function (<length> or resolvable <percentage>).
  333. // - An intrinsic sizing function (min-content, max-content, auto, fit-content()).
  334. // - A flexible sizing function (<flex>).
  335. // The grid sizing algorithm defines how to resolve these sizing constraints into used track sizes.
  336. struct GridTrack {
  337. CSS::GridTrackSize min_track_sizing_function;
  338. CSS::GridTrackSize max_track_sizing_function;
  339. float base_size { 0 };
  340. float growth_limit { 0 };
  341. };
  342. Vector<GridTrack> grid_rows;
  343. Vector<GridTrack> grid_columns;
  344. for (auto& column_size : box.computed_values().grid_template_columns())
  345. grid_columns.append({ column_size, column_size });
  346. for (auto& row_size : box.computed_values().grid_template_rows())
  347. grid_rows.append({ row_size, row_size });
  348. for (int column_index = grid_columns.size(); column_index < static_cast<int>(occupation_grid[0].size()); column_index++)
  349. grid_columns.append({ CSS::GridTrackSize::make_auto(), CSS::GridTrackSize::make_auto() });
  350. for (int row_index = grid_rows.size(); row_index < static_cast<int>(occupation_grid.size()); row_index++)
  351. grid_rows.append({ CSS::GridTrackSize::make_auto(), CSS::GridTrackSize::make_auto() });
  352. // https://drafts.csswg.org/css-grid/#algo-overview
  353. // 12.1. Grid Sizing Algorithm
  354. // FIXME: Deals with subgrids, min-content, and justify-content.. not implemented yet
  355. // https://drafts.csswg.org/css-grid/#algo-track-sizing
  356. // 12.3. Track Sizing Algorithm
  357. // The remainder of this section is the track sizing algorithm, which calculates from the min and
  358. // max track sizing functions the used track size. Each track has a base size, a <length> which
  359. // grows throughout the algorithm and which will eventually be the track’s final size, and a growth
  360. // limit, a <length> which provides a desired maximum size for the base size. There are 5 steps:
  361. // 1. Initialize Track Sizes
  362. // 2. Resolve Intrinsic Track Sizes
  363. // 3. Maximize Tracks
  364. // 4. Expand Flexible Tracks
  365. // 5. [[#algo-stretch|Expand Stretched auto Tracks]]
  366. // https://drafts.csswg.org/css-grid/#algo-init
  367. // 12.4. Initialize Track Sizes
  368. // Initialize each track’s base size and growth limit.
  369. for (auto& grid_column : grid_columns) {
  370. // For each track, if the track’s min track sizing function is:
  371. switch (grid_column.min_track_sizing_function.type()) {
  372. // - A fixed sizing function
  373. // Resolve to an absolute length and use that size as the track’s initial base size.
  374. // Indefinite lengths cannot occur, as they’re treated as auto.
  375. case CSS::GridTrackSize::Type::Length:
  376. if (!grid_column.min_track_sizing_function.length().is_auto())
  377. grid_column.base_size = grid_column.min_track_sizing_function.length().to_px(box);
  378. break;
  379. case CSS::GridTrackSize::Type::Percentage:
  380. grid_column.base_size = grid_column.min_track_sizing_function.percentage().as_fraction() * box_state.content_width();
  381. break;
  382. // - An intrinsic sizing function
  383. // Use an initial base size of zero.
  384. case CSS::GridTrackSize::Type::FlexibleLength:
  385. break;
  386. default:
  387. VERIFY_NOT_REACHED();
  388. }
  389. // For each track, if the track’s max track sizing function is:
  390. switch (grid_column.max_track_sizing_function.type()) {
  391. // - A fixed sizing function
  392. // Resolve to an absolute length and use that size as the track’s initial growth limit.
  393. case CSS::GridTrackSize::Type::Length:
  394. if (!grid_column.max_track_sizing_function.length().is_auto())
  395. grid_column.growth_limit = grid_column.max_track_sizing_function.length().to_px(box);
  396. else
  397. // - An intrinsic sizing function
  398. // Use an initial growth limit of infinity.
  399. grid_column.growth_limit = -1;
  400. break;
  401. case CSS::GridTrackSize::Type::Percentage:
  402. grid_column.growth_limit = grid_column.max_track_sizing_function.percentage().as_fraction() * box_state.content_width();
  403. break;
  404. // - A flexible sizing function
  405. // Use an initial growth limit of infinity.
  406. case CSS::GridTrackSize::Type::FlexibleLength:
  407. grid_column.growth_limit = -1;
  408. break;
  409. default:
  410. VERIFY_NOT_REACHED();
  411. }
  412. }
  413. // Initialize each track’s base size and growth limit.
  414. for (auto& grid_row : grid_rows) {
  415. // For each track, if the track’s min track sizing function is:
  416. switch (grid_row.min_track_sizing_function.type()) {
  417. // - A fixed sizing function
  418. // Resolve to an absolute length and use that size as the track’s initial base size.
  419. // Indefinite lengths cannot occur, as they’re treated as auto.
  420. case CSS::GridTrackSize::Type::Length:
  421. if (!grid_row.min_track_sizing_function.length().is_auto())
  422. grid_row.base_size = grid_row.min_track_sizing_function.length().to_px(box);
  423. break;
  424. case CSS::GridTrackSize::Type::Percentage:
  425. grid_row.base_size = grid_row.min_track_sizing_function.percentage().as_fraction() * box_state.content_height();
  426. break;
  427. // - An intrinsic sizing function
  428. // Use an initial base size of zero.
  429. case CSS::GridTrackSize::Type::FlexibleLength:
  430. break;
  431. default:
  432. VERIFY_NOT_REACHED();
  433. }
  434. // For each track, if the track’s max track sizing function is:
  435. switch (grid_row.max_track_sizing_function.type()) {
  436. // - A fixed sizing function
  437. // Resolve to an absolute length and use that size as the track’s initial growth limit.
  438. case CSS::GridTrackSize::Type::Length:
  439. if (!grid_row.max_track_sizing_function.length().is_auto())
  440. grid_row.growth_limit = grid_row.max_track_sizing_function.length().to_px(box);
  441. else
  442. // - An intrinsic sizing function
  443. // Use an initial growth limit of infinity.
  444. grid_row.growth_limit = -1;
  445. break;
  446. case CSS::GridTrackSize::Type::Percentage:
  447. grid_row.growth_limit = grid_row.max_track_sizing_function.percentage().as_fraction() * box_state.content_height();
  448. break;
  449. // - A flexible sizing function
  450. // Use an initial growth limit of infinity.
  451. case CSS::GridTrackSize::Type::FlexibleLength:
  452. grid_row.growth_limit = -1;
  453. break;
  454. default:
  455. VERIFY_NOT_REACHED();
  456. }
  457. }
  458. // FIXME: In all cases, if the growth limit is less than the base size, increase the growth limit to match
  459. // the base size.
  460. }
  461. }