3 #include "html_tag.h"
\r
5 void litehtml::table_grid::add_cell(element::ptr& el)
\r
9 cell.colspan = t_atoi(el->get_attr(_t("colspan"), _t("1")));
\r
10 cell.rowspan = t_atoi(el->get_attr(_t("rowspan"), _t("1")));
\r
11 cell.borders = el->get_borders();
\r
13 while( is_rowspanned( (int) m_cells.size() - 1, (int) m_cells.back().size() ) )
\r
15 m_cells.back().push_back(table_cell());
\r
18 m_cells.back().push_back(cell);
\r
19 for(int i = 1; i < cell.colspan; i++)
\r
21 table_cell empty_cell;
\r
22 m_cells.back().push_back(empty_cell);
\r
27 void litehtml::table_grid::begin_row(element::ptr& row)
\r
29 std::vector<table_cell> r;
\r
30 m_cells.push_back(r);
\r
32 m_rows.push_back(table_row(0, row));
\r
37 bool litehtml::table_grid::is_rowspanned( int r, int c )
\r
39 for(int row = r - 1; row >= 0; row--)
\r
41 if(c < (int) m_cells[row].size())
\r
43 if(m_cells[row][c].rowspan > 1)
\r
45 if(m_cells[row][c].rowspan >= r - row + 1)
\r
55 void litehtml::table_grid::finish()
\r
57 m_rows_count = (int) m_cells.size();
\r
59 for(int i = 0; i < (int) m_cells.size(); i++)
\r
61 m_cols_count = std::max(m_cols_count, (int) m_cells[i].size());
\r
63 for(int i = 0; i < (int) m_cells.size(); i++)
\r
65 for(int j = (int) m_cells[i].size(); j < m_cols_count; j++)
\r
67 table_cell empty_cell;
\r
68 m_cells[i].push_back(empty_cell);
\r
73 for(int i = 0; i < m_cols_count; i++)
\r
75 m_columns.push_back(table_column(0, 0));
\r
78 for(int col = 0; col < m_cols_count; col++)
\r
80 for(int row = 0; row < m_rows_count; row++)
\r
82 if(cell(col, row)->el)
\r
84 // find minimum left border width
\r
85 if(m_columns[col].border_left)
\r
87 m_columns[col].border_left = std::min(m_columns[col].border_left, cell(col, row)->borders.left);
\r
90 m_columns[col].border_left = cell(col, row)->borders.left;
\r
92 // find minimum right border width
\r
93 if(m_columns[col].border_right)
\r
95 m_columns[col].border_right = std::min(m_columns[col].border_right, cell(col, row)->borders.right);
\r
98 m_columns[col].border_right = cell(col, row)->borders.right;
\r
100 // find minimum top border width
\r
101 if(m_rows[row].border_top)
\r
103 m_rows[row].border_top = std::min(m_rows[row].border_top, cell(col, row)->borders.top);
\r
106 m_rows[row].border_top = cell(col, row)->borders.top;
\r
108 // find minimum bottom border width
\r
109 if(m_rows[row].border_bottom)
\r
111 m_rows[row].border_bottom = std::min(m_rows[row].border_bottom, cell(col, row)->borders.bottom);
\r
114 m_rows[row].border_bottom = cell(col, row)->borders.bottom;
\r
118 if(cell(col, row)->el && cell(col, row)->colspan <= 1)
\r
120 if (!cell(col, row)->el->get_css_width().is_predefined() && m_columns[col].css_width.is_predefined())
\r
122 m_columns[col].css_width = cell(col, row)->el->get_css_width();
\r
128 for(int col = 0; col < m_cols_count; col++)
\r
130 for(int row = 0; row < m_rows_count; row++)
\r
132 if(cell(col, row)->el)
\r
134 cell(col, row)->el->set_css_width(m_columns[col].css_width);
\r
140 litehtml::table_cell* litehtml::table_grid::cell( int t_col, int t_row )
\r
142 if(t_col >= 0 && t_col < m_cols_count && t_row >= 0 && t_row < m_rows_count)
\r
144 return &m_cells[t_row][t_col];
\r
149 void litehtml::table_grid::distribute_max_width( int width, int start, int end )
\r
151 table_column_accessor_max_width selector;
\r
152 distribute_width(width, start, end, &selector);
\r
155 void litehtml::table_grid::distribute_min_width( int width, int start, int end )
\r
157 table_column_accessor_min_width selector;
\r
158 distribute_width(width, start, end, &selector);
\r
161 void litehtml::table_grid::distribute_width( int width, int start, int end, table_column_accessor* acc )
\r
163 if(!(start >= 0 && start < m_cols_count && end >= 0 && end < m_cols_count))
\r
168 int cols_width = 0;
\r
169 for(int col = start; col <= end; col++)
\r
171 cols_width += m_columns[col].max_width;
\r
174 int add = width / (end - start + 1);
\r
175 int added_width = 0;
\r
176 for(int col = start; col <= end; col++)
\r
180 add = round_f( (float) width * ((float) m_columns[col].max_width / (float) cols_width) );
\r
182 added_width += add;
\r
183 acc->get(m_columns[col]) += add;
\r
185 if(added_width < width)
\r
187 acc->get(m_columns[start]) += width - added_width;
\r
191 void litehtml::table_grid::distribute_width( int width, int start, int end )
\r
193 if(!(start >= 0 && start < m_cols_count && end >= 0 && end < m_cols_count))
\r
198 std::vector<table_column*> distribute_columns;
\r
200 for(int step = 0; step < 3; step++)
\r
202 distribute_columns.clear();
\r
208 // distribute between the columns with width == auto
\r
209 for(int col = start; col <= end; col++)
\r
211 if(m_columns[col].css_width.is_predefined())
\r
213 distribute_columns.push_back(&m_columns[col]);
\r
220 // distribute between the columns with percents
\r
221 for(int col = start; col <= end; col++)
\r
223 if(!m_columns[col].css_width.is_predefined() && m_columns[col].css_width.units() == css_units_percentage)
\r
225 distribute_columns.push_back(&m_columns[col]);
\r
232 //well distribute between all columns
\r
233 for(int col = start; col <= end; col++)
\r
235 distribute_columns.push_back(&m_columns[col]);
\r
241 int added_width = 0;
\r
243 if(!distribute_columns.empty() || step == 2)
\r
245 int cols_width = 0;
\r
246 for(std::vector<table_column*>::iterator col = distribute_columns.begin(); col != distribute_columns.end(); col++)
\r
248 cols_width += (*col)->max_width - (*col)->min_width;
\r
253 int add = width / (int) distribute_columns.size();
\r
254 for(std::vector<table_column*>::iterator col = distribute_columns.begin(); col != distribute_columns.end(); col++)
\r
256 add = round_f( (float) width * ((float) ((*col)->max_width - (*col)->min_width) / (float) cols_width) );
\r
257 if((*col)->width + add >= (*col)->min_width)
\r
259 (*col)->width += add;
\r
260 added_width += add;
\r
263 added_width += ((*col)->width - (*col)->min_width) * (add / abs(add));
\r
264 (*col)->width = (*col)->min_width;
\r
267 if(added_width < width && step)
\r
269 distribute_columns.front()->width += width - added_width;
\r
270 added_width = width;
\r
274 distribute_columns.back()->width += width;
\r
275 added_width = width;
\r
279 if(added_width == width)
\r
284 width -= added_width;
\r
289 int litehtml::table_grid::calc_table_width(int block_width, bool is_auto, int& min_table_width, int& max_table_width)
\r
291 //int table_width = 0;
\r
293 min_table_width = 0; // MIN
\r
294 max_table_width = 0; // MAX
\r
300 for(int col = 0; col < m_cols_count; col++)
\r
302 min_table_width += m_columns[col].min_width;
\r
303 max_table_width += m_columns[col].max_width;
\r
305 if(!m_columns[col].css_width.is_predefined())
\r
307 m_columns[col].width = m_columns[col].css_width.calc_percent(block_width);
\r
308 m_columns[col].width = std::max(m_columns[col].width, m_columns[col].min_width);
\r
311 m_columns[col].width = m_columns[col].min_width;
\r
312 max_w += m_columns[col].max_width;
\r
313 min_w += m_columns[col].min_width;
\r
316 cur_width += m_columns[col].width;
\r
319 if(cur_width == block_width)
\r
324 if(cur_width < block_width)
\r
326 if(cur_width - min_w + max_w <= block_width)
\r
329 for(int col = 0; col < m_cols_count; col++)
\r
331 if(m_columns[col].css_width.is_predefined())
\r
333 m_columns[col].width = m_columns[col].max_width;
\r
335 cur_width += m_columns[col].width;
\r
337 if(cur_width == block_width || is_auto)
\r
342 distribute_width(block_width - cur_width, 0, m_cols_count - 1);
\r
344 for(int col = 0; col < m_cols_count; col++)
\r
346 cur_width += m_columns[col].width;
\r
350 int fixed_width = 0;
\r
352 for(int col = 0; col < m_cols_count; col++)
\r
354 if(!m_columns[col].css_width.is_predefined() && m_columns[col].css_width.units() == css_units_percentage)
\r
356 percent += m_columns[col].css_width.val();
\r
359 fixed_width += m_columns[col].width;
\r
362 float scale = (float) (100.0 / percent);
\r
364 for(int col = 0; col < m_cols_count; col++)
\r
366 if(!m_columns[col].css_width.is_predefined() && m_columns[col].css_width.units() == css_units_percentage)
\r
369 w.set_value(m_columns[col].css_width.val() * scale, css_units_percentage);
\r
370 m_columns[col].width = w.calc_percent(block_width - fixed_width);
\r
371 if(m_columns[col].width < m_columns[col].min_width)
\r
373 m_columns[col].width = m_columns[col].min_width;
\r
376 cur_width += m_columns[col].width;
\r
382 void litehtml::table_grid::clear()
\r
391 void litehtml::table_grid::calc_horizontal_positions( margins& table_borders, border_collapse bc, int bdr_space_x)
\r
393 if(bc == border_collapse_separate)
\r
395 int left = bdr_space_x;
\r
396 for(int i = 0; i < m_cols_count; i++)
\r
398 m_columns[i].left = left;
\r
399 m_columns[i].right = m_columns[i].left + m_columns[i].width;
\r
400 left = m_columns[i].right + bdr_space_x;
\r
407 left -= std::min(table_borders.left, m_columns[0].border_left);
\r
409 for(int i = 0; i < m_cols_count; i++)
\r
413 left -= std::min(m_columns[i - 1].border_right, m_columns[i].border_left);
\r
416 m_columns[i].left = left;
\r
417 m_columns[i].right = m_columns[i].left + m_columns[i].width;
\r
418 left = m_columns[i].right;
\r
423 void litehtml::table_grid::calc_vertical_positions( margins& table_borders, border_collapse bc, int bdr_space_y )
\r
425 if(bc == border_collapse_separate)
\r
427 int top = bdr_space_y;
\r
428 for(int i = 0; i < m_rows_count; i++)
\r
430 m_rows[i].top = top;
\r
431 m_rows[i].bottom = m_rows[i].top + m_rows[i].height;
\r
432 top = m_rows[i].bottom + bdr_space_y;
\r
439 top -= std::min(table_borders.top, m_rows[0].border_top);
\r
441 for(int i = 0; i < m_rows_count; i++)
\r
445 top -= std::min(m_rows[i - 1].border_bottom, m_rows[i].border_top);
\r
448 m_rows[i].top = top;
\r
449 m_rows[i].bottom = m_rows[i].top + m_rows[i].height;
\r
450 top = m_rows[i].bottom;
\r
455 void litehtml::table_grid::calc_rows_height(int blockHeight, int borderSpacingY)
\r
457 int min_table_height = 0;
\r
459 // compute vertical size inferred by cells
\r
460 for (auto& row : m_rows)
\r
462 if (!row.css_height.is_predefined())
\r
464 if (row.css_height.units() != css_units_percentage)
\r
466 if (row.height < (int)row.css_height.val())
\r
468 row.height = (int)row.css_height.val();
\r
472 row.min_height = row.height;
\r
473 min_table_height += row.height;
\r
476 //min_table_height += borderSpacingY * ((int) m_rows.size() + 1);
\r
478 if (blockHeight > min_table_height)
\r
480 int extra_height = blockHeight - min_table_height;
\r
481 int auto_count = 0; // number of rows with height=auto
\r
482 for (auto& row : m_rows)
\r
484 if (!row.css_height.is_predefined() && row.css_height.units() == css_units_percentage)
\r
486 row.height = row.css_height.calc_percent(blockHeight);
\r
487 if (row.height < row.min_height)
\r
489 row.height = row.min_height;
\r
492 extra_height -= row.height - row.min_height;
\r
494 if (extra_height <= 0) break;
\r
496 else if (row.css_height.is_predefined())
\r
501 if (extra_height > 0)
\r
505 // distribute height to the rows with height=auto
\r
506 int extra_row_height = (int)(extra_height / auto_count);
\r
507 for (auto& row : m_rows)
\r
509 if (row.css_height.is_predefined())
\r
511 row.height += extra_row_height;
\r
517 // We don't have rows with height=auto, so distribute height to all rows
\r
518 if (!m_rows.empty())
\r
520 int extra_row_height = (int)(extra_height / m_rows.size());
\r
521 for (auto& row : m_rows)
\r
523 row.height += extra_row_height;
\r
528 else if (extra_height < 0)
\r
530 extra_height = -extra_height;
\r
531 for (auto row = m_rows.rbegin(); row < m_rows.rend() && extra_height > 0; row++)
\r
533 if (row->height > row->min_height)
\r
535 if (row->height - extra_height >= row->min_height)
\r
537 row->height -= extra_height;
\r
542 extra_height -= row->height - row->min_height;
\r
543 row->height = row->min_height;
\r
551 //////////////////////////////////////////////////////////////////////////
\r
553 int& litehtml::table_column_accessor_max_width::get( table_column& col )
\r
555 return col.max_width;
\r
558 int& litehtml::table_column_accessor_min_width::get( table_column& col )
\r
560 return col.min_width;
\r
563 int& litehtml::table_column_accessor_width::get( table_column& col )
\r