NC_ not working here, remove it
[claws.git] / src / plugins / litehtml_viewer / litehtml / table.cpp
blobda272c07072434382de192a7d18b4c8e9409c0f1
1 #include "html.h"
2 #include "table.h"
3 #include "element.h"
4 #include "render_item.h"
6 void litehtml::table_grid::add_cell(const std::shared_ptr<render_item>& el)
8 table_cell cell;
9 cell.el = el;
10 cell.colspan = atoi(el->src_el()->get_attr("colspan", "1"));
11 cell.rowspan = atoi(el->src_el()->get_attr("rowspan", "1"));
12 cell.borders = el->get_borders();
14 while( is_rowspanned( (int) m_cells.size() - 1, (int) m_cells.back().size() ) )
16 m_cells.back().push_back(table_cell());
19 m_cells.back().push_back(cell);
20 for(int i = 1; i < cell.colspan; i++)
22 table_cell empty_cell;
23 m_cells.back().push_back(empty_cell);
28 void litehtml::table_grid::begin_row(const std::shared_ptr<render_item>& row)
30 std::vector<table_cell> r;
31 m_cells.push_back(r);
33 m_rows.push_back(table_row(0, row));
37 bool litehtml::table_grid::is_rowspanned( int r, int c )
39 for(int row = r - 1; row >= 0; row--)
41 if(c < (int) m_cells[row].size())
43 if(m_cells[row][c].rowspan > 1)
45 if(m_cells[row][c].rowspan >= r - row + 1)
47 return true;
52 return false;
55 void litehtml::table_grid::finish()
57 m_rows_count = (int) m_cells.size();
58 m_cols_count = 0;
59 for(auto& cell : m_cells)
61 m_cols_count = std::max(m_cols_count, (int) cell.size());
63 for(auto& cell : m_cells)
65 for(int j = (int) cell.size(); j < m_cols_count; j++)
67 table_cell empty_cell;
68 cell.push_back(empty_cell);
72 m_columns.clear();
73 for(int i = 0; i < m_cols_count; i++)
75 m_columns.push_back(table_column(0, 0));
78 for(int col = 0; col < m_cols_count; col++)
80 for(int row = 0; row < m_rows_count; row++)
82 if(cell(col, row)->el)
84 // find minimum left border width
85 if(m_columns[col].border_left)
87 m_columns[col].border_left = std::min(m_columns[col].border_left, cell(col, row)->borders.left);
88 } else
90 m_columns[col].border_left = cell(col, row)->borders.left;
92 // find minimum right border width
93 if(m_columns[col].border_right)
95 m_columns[col].border_right = std::min(m_columns[col].border_right, cell(col, row)->borders.right);
96 } else
98 m_columns[col].border_right = cell(col, row)->borders.right;
100 // find minimum top border width
101 if(m_rows[row].border_top)
103 m_rows[row].border_top = std::min(m_rows[row].border_top, cell(col, row)->borders.top);
104 } else
106 m_rows[row].border_top = cell(col, row)->borders.top;
108 // find minimum bottom border width
109 if(m_rows[row].border_bottom)
111 m_rows[row].border_bottom = std::min(m_rows[row].border_bottom, cell(col, row)->borders.bottom);
112 } else
114 m_rows[row].border_bottom = cell(col, row)->borders.bottom;
118 if(cell(col, row)->el && cell(col, row)->colspan <= 1)
120 if (!cell(col, row)->el->src_el()->css().get_width().is_predefined() && m_columns[col].css_width.is_predefined())
122 m_columns[col].css_width = cell(col, row)->el->src_el()->css().get_width();
128 for(int col = 0; col < m_cols_count; col++)
130 for(int row = 0; row < m_rows_count; row++)
132 if(cell(col, row)->el && cell(col, row)->colspan == 1)
134 cell(col, row)->el->src_el()->css_w().set_width(m_columns[col].css_width);
140 litehtml::table_cell* litehtml::table_grid::cell( int t_col, int t_row )
142 if(t_col >= 0 && t_col < m_cols_count && t_row >= 0 && t_row < m_rows_count)
144 return &m_cells[t_row][t_col];
146 return nullptr;
149 void litehtml::table_grid::distribute_max_width( int width, int start, int end )
151 table_column_accessor_max_width selector;
152 distribute_width(width, start, end, &selector);
155 void litehtml::table_grid::distribute_min_width( int width, int start, int end )
157 table_column_accessor_min_width selector;
158 distribute_width(width, start, end, &selector);
161 void litehtml::table_grid::distribute_width( int width, int start, int end, table_column_accessor* acc )
163 if(!(start >= 0 && start < m_cols_count && end >= 0 && end < m_cols_count))
165 return;
168 int cols_width = 0;
169 for(int col = start; col <= end; col++)
171 cols_width += m_columns[col].max_width;
174 int add = width / (end - start + 1);
175 int added_width = 0;
176 for(int col = start; col <= end; col++)
178 if(cols_width)
180 add = round_f( (float) width * ((float) m_columns[col].max_width / (float) cols_width) );
182 added_width += add;
183 acc->get(m_columns[col]) += add;
185 if(added_width < width)
187 acc->get(m_columns[start]) += width - added_width;
191 void litehtml::table_grid::distribute_width( int width, int start, int end )
193 if(!(start >= 0 && start < m_cols_count && end >= 0 && end < m_cols_count))
195 return;
198 std::vector<table_column*> distribute_columns;
200 for(int step = 0; step < 3; step++)
202 distribute_columns.clear();
204 switch(step)
206 case 0:
208 // distribute between the columns with width == auto
209 for(int col = start; col <= end; col++)
211 if(m_columns[col].css_width.is_predefined())
213 distribute_columns.push_back(&m_columns[col]);
217 break;
218 case 1:
220 // distribute between the columns with percents
221 for(int col = start; col <= end; col++)
223 if(!m_columns[col].css_width.is_predefined() && m_columns[col].css_width.units() == css_units_percentage)
225 distribute_columns.push_back(&m_columns[col]);
229 break;
230 case 2:
232 //well distribute between all columns
233 for(int col = start; col <= end; col++)
235 distribute_columns.push_back(&m_columns[col]);
238 break;
241 int added_width = 0;
243 if(!distribute_columns.empty() || step == 2)
245 int cols_width = 0;
246 for(const auto& column : distribute_columns)
248 cols_width += column->max_width - column->min_width;
251 if(cols_width)
253 int add = width / (int) distribute_columns.size();
254 for(const auto& column : distribute_columns)
256 add = round_f( (float) width * ((float) (column->max_width - column->min_width) / (float) cols_width) );
257 if(column->width + add >= column->min_width)
259 column->width += add;
260 added_width += add;
261 } else
263 added_width += (column->width - column->min_width) * (add / abs(add));
264 column->width = column->min_width;
267 if(added_width < width && step)
269 distribute_columns.front()->width += width - added_width;
270 added_width = width;
272 } else
274 distribute_columns.back()->width += width;
275 added_width = width;
279 if(added_width == width)
281 break;
282 } else
284 width -= added_width;
289 int litehtml::table_grid::calc_table_width(int block_width, bool is_auto, int& min_table_width, int& max_table_width)
291 //int table_width = 0;
293 min_table_width = 0; // MIN
294 max_table_width = 0; // MAX
296 int cur_width = 0;
297 int max_w = 0;
298 int min_w = 0;
300 for(int col = 0; col < m_cols_count; col++)
302 min_table_width += m_columns[col].min_width;
303 max_table_width += m_columns[col].max_width;
305 if(!m_columns[col].css_width.is_predefined())
307 m_columns[col].width = m_columns[col].css_width.calc_percent(block_width);
308 m_columns[col].width = std::max(m_columns[col].width, m_columns[col].min_width);
309 } else
311 m_columns[col].width = m_columns[col].min_width;
312 max_w += m_columns[col].max_width;
313 min_w += m_columns[col].min_width;
316 cur_width += m_columns[col].width;
319 if(cur_width == block_width)
321 return cur_width;
324 if(cur_width < block_width)
326 if(cur_width - min_w + max_w <= block_width)
328 cur_width = 0;
329 for(int col = 0; col < m_cols_count; col++)
331 if(m_columns[col].css_width.is_predefined())
333 m_columns[col].width = m_columns[col].max_width;
335 cur_width += m_columns[col].width;
337 if(cur_width == block_width || is_auto)
339 return cur_width;
342 distribute_width(block_width - cur_width, 0, m_cols_count - 1);
343 cur_width = 0;
344 for(int col = 0; col < m_cols_count; col++)
346 cur_width += m_columns[col].width;
348 } else
350 int fixed_width = 0;
351 float percent = 0;
352 for(int col = 0; col < m_cols_count; col++)
354 if(!m_columns[col].css_width.is_predefined() && m_columns[col].css_width.units() == css_units_percentage)
356 percent += m_columns[col].css_width.val();
357 } else
359 fixed_width += m_columns[col].width;
362 auto scale = (float) (100.0 / percent);
363 cur_width = 0;
364 for(int col = 0; col < m_cols_count; col++)
366 if(!m_columns[col].css_width.is_predefined() && m_columns[col].css_width.units() == css_units_percentage)
368 css_length w;
369 w.set_value(m_columns[col].css_width.val() * scale, css_units_percentage);
370 m_columns[col].width = w.calc_percent(block_width - fixed_width);
371 if(m_columns[col].width < m_columns[col].min_width)
373 m_columns[col].width = m_columns[col].min_width;
376 cur_width += m_columns[col].width;
378 // If the table is still too wide shrink columns with % widths
379 if(cur_width > block_width)
381 while(true)
383 bool shrunk = false;
384 for(int col = 0; col < m_cols_count; col++)
386 if(!m_columns[col].css_width.is_predefined() && m_columns[col].css_width.units() == css_units_percentage)
388 if(m_columns[col].width > m_columns[col].min_width)
390 m_columns[col].width--;
391 cur_width--;
392 shrunk = true;
393 if(cur_width == block_width)
395 break;
400 if(cur_width == block_width || !shrunk)
402 break;
407 return cur_width;
410 void litehtml::table_grid::clear()
412 m_rows_count = 0;
413 m_cols_count = 0;
414 m_cells.clear();
415 m_columns.clear();
416 m_rows.clear();
419 void litehtml::table_grid::calc_horizontal_positions( const margins& table_borders, border_collapse bc, int bdr_space_x)
421 if(bc == border_collapse_separate)
423 int left = bdr_space_x;
424 for(int i = 0; i < m_cols_count; i++)
426 m_columns[i].left = left;
427 m_columns[i].right = m_columns[i].left + m_columns[i].width;
428 left = m_columns[i].right + bdr_space_x;
430 } else
432 int left = 0;
433 if(m_cols_count)
435 left -= std::min(table_borders.left, m_columns[0].border_left);
437 for(int i = 0; i < m_cols_count; i++)
439 if(i > 0)
441 left -= std::min(m_columns[i - 1].border_right, m_columns[i].border_left);
444 m_columns[i].left = left;
445 m_columns[i].right = m_columns[i].left + m_columns[i].width;
446 left = m_columns[i].right;
451 void litehtml::table_grid::calc_vertical_positions( const margins& table_borders, border_collapse bc, int bdr_space_y )
453 if(bc == border_collapse_separate)
455 int top = bdr_space_y;
456 for(int i = 0; i < m_rows_count; i++)
458 m_rows[i].top = top;
459 m_rows[i].bottom = m_rows[i].top + m_rows[i].height;
460 top = m_rows[i].bottom + bdr_space_y;
462 } else
464 int top = 0;
465 if(m_rows_count)
467 top -= std::min(table_borders.top, m_rows[0].border_top);
469 for(int i = 0; i < m_rows_count; i++)
471 if(i > 0)
473 top -= std::min(m_rows[i - 1].border_bottom, m_rows[i].border_top);
476 m_rows[i].top = top;
477 m_rows[i].bottom = m_rows[i].top + m_rows[i].height;
478 top = m_rows[i].bottom;
483 void litehtml::table_grid::calc_rows_height(int blockHeight, int borderSpacingY)
485 int min_table_height = 0;
487 // compute vertical size inferred by cells
488 for (auto& row : m_rows)
490 if (!row.css_height.is_predefined())
492 if (row.css_height.units() != css_units_percentage)
494 if (row.height < (int)row.css_height.val())
496 row.height = (int)row.css_height.val();
500 row.min_height = row.height;
501 min_table_height += row.height;
504 //min_table_height += borderSpacingY * ((int) m_rows.size() + 1);
506 if (blockHeight > min_table_height)
508 int extra_height = blockHeight - min_table_height;
509 int auto_count = 0; // number of rows with height=auto
510 for (auto& row : m_rows)
512 if (!row.css_height.is_predefined() && row.css_height.units() == css_units_percentage)
514 row.height = row.css_height.calc_percent(blockHeight);
515 if (row.height < row.min_height)
517 row.height = row.min_height;
520 extra_height -= row.height - row.min_height;
522 if (extra_height <= 0) break;
524 else if (row.css_height.is_predefined())
526 auto_count++;
529 if (extra_height > 0)
531 if (auto_count)
533 // distribute height to the rows with height=auto
534 int extra_row_height = (int)(extra_height / auto_count);
535 for (auto& row : m_rows)
537 if (row.css_height.is_predefined())
539 row.height += extra_row_height;
543 else
545 // We don't have rows with height=auto, so distribute height to all rows
546 if (!m_rows.empty())
548 int extra_row_height = (int)(extra_height / m_rows.size());
549 for (auto& row : m_rows)
551 row.height += extra_row_height;
556 else if (extra_height < 0)
558 extra_height = -extra_height;
559 for (auto row = m_rows.rbegin(); row < m_rows.rend() && extra_height > 0; row++)
561 if (row->height > row->min_height)
563 if (row->height - extra_height >= row->min_height)
565 row->height -= extra_height;
566 extra_height = 0;
568 else
570 extra_height -= row->height - row->min_height;
571 row->height = row->min_height;
579 //////////////////////////////////////////////////////////////////////////
581 int& litehtml::table_column_accessor_max_width::get( table_column& col )
583 return col.max_width;
586 int& litehtml::table_column_accessor_min_width::get( table_column& col )
588 return col.min_width;
591 int& litehtml::table_column_accessor_width::get( table_column& col )
593 return col.width;
596 litehtml::table_row::table_row(int h, const std::shared_ptr<render_item>& row)
598 min_height = 0;
599 height = h;
600 el_row = row;
601 border_bottom = 0;
602 border_top = 0;
603 top = 0;
604 bottom = 0;
605 if (row)
607 css_height = row->src_el()->css().get_height();