4 #include "render_item.h"
6 void litehtml::table_grid::add_cell(const std::shared_ptr
<render_item
>& 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
;
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)
55 void litehtml::table_grid::finish()
57 m_rows_count
= (int) m_cells
.size();
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
);
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
);
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
);
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
);
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
);
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
];
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
))
169 for(int col
= start
; col
<= end
; col
++)
171 cols_width
+= m_columns
[col
].max_width
;
174 int add
= width
/ (end
- start
+ 1);
176 for(int col
= start
; col
<= end
; col
++)
180 add
= round_f( (float) width
* ((float) m_columns
[col
].max_width
/ (float) cols_width
) );
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
))
198 std::vector
<table_column
*> distribute_columns
;
200 for(int step
= 0; step
< 3; step
++)
202 distribute_columns
.clear();
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
]);
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
]);
232 //well distribute between all columns
233 for(int col
= start
; col
<= end
; col
++)
235 distribute_columns
.push_back(&m_columns
[col
]);
243 if(!distribute_columns
.empty() || step
== 2)
246 for(const auto& column
: distribute_columns
)
248 cols_width
+= column
->max_width
- column
->min_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
;
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
;
274 distribute_columns
.back()->width
+= width
;
279 if(added_width
== width
)
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
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
);
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
)
324 if(cur_width
< block_width
)
326 if(cur_width
- min_w
+ max_w
<= block_width
)
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
)
342 distribute_width(block_width
- cur_width
, 0, m_cols_count
- 1);
344 for(int col
= 0; col
< m_cols_count
; col
++)
346 cur_width
+= m_columns
[col
].width
;
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();
359 fixed_width
+= m_columns
[col
].width
;
362 auto scale
= (float) (100.0 / percent
);
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
)
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
)
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
--;
393 if(cur_width
== block_width
)
400 if(cur_width
== block_width
|| !shrunk
)
410 void litehtml::table_grid::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
;
435 left
-= std::min(table_borders
.left
, m_columns
[0].border_left
);
437 for(int i
= 0; i
< m_cols_count
; i
++)
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
++)
459 m_rows
[i
].bottom
= m_rows
[i
].top
+ m_rows
[i
].height
;
460 top
= m_rows
[i
].bottom
+ bdr_space_y
;
467 top
-= std::min(table_borders
.top
, m_rows
[0].border_top
);
469 for(int i
= 0; i
< m_rows_count
; i
++)
473 top
-= std::min(m_rows
[i
- 1].border_bottom
, m_rows
[i
].border_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())
529 if (extra_height
> 0)
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
;
545 // We don't have rows with height=auto, so distribute height to all rows
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
;
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
)
596 litehtml::table_row::table_row(int h
, const std::shared_ptr
<render_item
>& row
)
607 css_height
= row
->src_el()->css().get_height();