3 #include "render_item.h"
7 void litehtml::flex_item::init(const litehtml::containing_block_context
&self_size
,
8 litehtml::formatting_context
*fmt_ctx
, flex_align_items align_items
)
10 grow
= (int) std::nearbyint(el
->css().get_flex_grow() * 1000.0);
11 // Negative numbers are invalid.
12 // https://www.w3.org/TR/css-flexbox-1/#valdef-flex-grow-number
13 if(grow
< 0) grow
= 0;
15 shrink
= (int) std::nearbyint(el
->css().get_flex_shrink() * 1000.0);
16 // Negative numbers are invalid.
17 // https://www.w3.org/TR/css-flexbox-1/#valdef-flex-shrink-number
18 if(shrink
< 0) shrink
= 1000;
20 el
->calc_outlines(self_size
.render_width
);
21 order
= el
->css().get_order();
23 direction_specific_init(self_size
, fmt_ctx
);
25 if (el
->css().get_flex_align_self() == flex_align_items_auto
)
30 align
= el
->css().get_flex_align_self();
32 main_size
= base_size
;
33 scaled_flex_shrink_factor
= base_size
* shrink
;
37 void litehtml::flex_item::place(flex_line
&ln
, int main_pos
,
38 const containing_block_context
&self_size
,
39 formatting_context
*fmt_ctx
)
41 apply_main_auto_margins();
42 set_main_position(main_pos
);
43 if(!apply_cross_auto_margins(ln
.cross_size
))
47 case flex_align_items_baseline
:
48 align_baseline(ln
, self_size
, fmt_ctx
);
50 case flex_align_items_flex_end
:
53 set_cross_position(ln
.cross_start
);
54 break; /// If cross axis is reversed position item from start
56 case flex_align_items_end
:
57 set_cross_position(ln
.cross_start
+ ln
.cross_size
- get_el_cross_size());
59 case flex_align_items_center
:
60 set_cross_position(ln
.cross_start
+ ln
.cross_size
/ 2 - get_el_cross_size() / 2);
62 case flex_align_items_flex_start
:
63 if(ln
.reverse_cross
) /// If cross axis is reversed position item from end
65 set_cross_position(ln
.cross_start
+ ln
.cross_size
- get_el_cross_size());
68 case flex_align_items_start
:
69 set_cross_position(ln
.cross_start
);
72 align_stretch(ln
, self_size
, fmt_ctx
);
78 int litehtml::flex_item::get_last_baseline(baseline::_baseline_type type
) const
80 if(type
== baseline::baseline_type_top
)
82 return el
->get_last_baseline();
83 } else if(type
== baseline::baseline_type_bottom
)
85 return el
->height() - el
->get_last_baseline();
90 int litehtml::flex_item::get_first_baseline(litehtml::baseline::_baseline_type type
) const
92 if(type
== baseline::baseline_type_top
)
94 return el
->get_first_baseline();
95 } else if(type
== baseline::baseline_type_bottom
)
97 return el
->height() - el
->get_first_baseline();
103 ////////////////////////////////////////////////////////////////////////////////////
105 void litehtml::flex_item_row_direction::direction_specific_init(const litehtml::containing_block_context
&self_size
,
106 litehtml::formatting_context
*fmt_ctx
)
108 if(el
->css().get_margins().left
.is_predefined())
110 auto_margin_main_start
= 0;
112 if(el
->css().get_margins().right
.is_predefined())
114 auto_margin_main_end
= 0;
116 if(el
->css().get_margins().top
.is_predefined())
118 auto_margin_cross_start
= true;
120 if(el
->css().get_margins().bottom
.is_predefined())
122 auto_margin_cross_end
= true;
124 def_value
<int> content_size(0);
125 if (el
->css().get_min_width().is_predefined())
127 min_size
= el
->render(0, 0,
128 self_size
.new_width(el
->content_offset_width(),
129 containing_block_context::size_mode_content
), fmt_ctx
);
130 content_size
= min_size
;
133 min_size
= el
->css().get_min_width().calc_percent(self_size
.render_width
) +
134 el
->content_offset_width();
136 if (!el
->css().get_max_width().is_predefined())
138 max_size
= el
->css().get_max_width().calc_percent(self_size
.render_width
) +
139 el
->content_offset_width();
141 bool flex_basis_predefined
= el
->css().get_flex_basis().is_predefined();
142 int predef
= flex_basis_auto
;
143 if(flex_basis_predefined
)
145 predef
= el
->css().get_flex_basis().predef();
148 if(el
->css().get_flex_basis().val() < 0)
150 flex_basis_predefined
= true;
154 if (flex_basis_predefined
)
158 case flex_basis_auto
:
159 if (!el
->css().get_width().is_predefined())
161 base_size
= el
->css().get_width().calc_percent(self_size
.render_width
) +
162 el
->content_offset_width();
165 // if width is not predefined, use content size as base size
166 case flex_basis_fit_content
:
167 case flex_basis_content
:
168 base_size
= el
->render(0, 0, self_size
.new_width(self_size
.render_width
+ el
->content_offset_width(),
169 containing_block_context::size_mode_content
|
170 containing_block_context::size_mode_exact_width
),
173 case flex_basis_min_content
:
174 if(content_size
.is_default())
176 content_size
= el
->render(0, 0,
177 self_size
.new_width(el
->content_offset_width(),
178 containing_block_context::size_mode_content
),
181 base_size
= content_size
;
183 case flex_basis_max_content
:
184 el
->render(0, 0, self_size
, fmt_ctx
);
185 base_size
= el
->width();
193 base_size
= el
->css().get_flex_basis().calc_percent(self_size
.render_width
) +
194 el
->content_offset_width();
195 base_size
= std::max(base_size
, min_size
);
199 void litehtml::flex_item_row_direction::apply_main_auto_margins()
201 // apply auto margins to item
202 if(!auto_margin_main_start
.is_default())
204 el
->get_margins().left
= auto_margin_main_start
;
205 el
->pos().x
+= auto_margin_main_start
;
207 if(!auto_margin_main_end
.is_default()) el
->get_margins().right
= auto_margin_main_end
;
210 bool litehtml::flex_item_row_direction::apply_cross_auto_margins(int cross_size
)
212 if(auto_margin_cross_end
|| auto_margin_cross_start
)
215 if(auto_margin_cross_end
)
219 if(auto_margin_cross_start
)
223 int margin
= (cross_size
- el
->height()) / margins_num
;
224 if(auto_margin_cross_start
)
226 el
->get_margins().top
= margin
;
227 el
->pos().y
= el
->content_offset_top();
229 if(auto_margin_cross_end
)
231 el
->get_margins().bottom
= margin
;
238 void litehtml::flex_item_row_direction::set_main_position(int pos
)
240 el
->pos().x
= pos
+ el
->content_offset_left();
243 void litehtml::flex_item_row_direction::set_cross_position(int pos
)
245 el
->pos().y
= pos
+ el
->content_offset_top();
248 void litehtml::flex_item_row_direction::align_stretch(flex_line
&ln
, const containing_block_context
&self_size
,
249 formatting_context
*fmt_ctx
)
251 set_cross_position(ln
.cross_start
);
252 if (el
->css().get_height().is_predefined())
254 el
->render(el
->left(), el
->top(), self_size
.new_width_height(
255 el
->pos().width
+ el
->box_sizing_width(),
256 ln
.cross_size
- el
->content_offset_height() + el
->box_sizing_height(),
257 containing_block_context::size_mode_exact_width
|
258 containing_block_context::size_mode_exact_height
260 apply_main_auto_margins();
264 void litehtml::flex_item_row_direction::align_baseline(litehtml::flex_line
&ln
,
265 const containing_block_context
&self_size
,
266 formatting_context
*fmt_ctx
)
268 if (align
& flex_align_items_last
)
270 set_cross_position(ln
.cross_start
+ ln
.last_baseline
.get_offset_from_top(ln
.cross_size
) - el
->get_last_baseline());
273 set_cross_position(ln
.cross_start
+ ln
.first_baseline
.get_offset_from_top(ln
.cross_size
) - el
->get_first_baseline());
277 int litehtml::flex_item_row_direction::get_el_main_size()
282 int litehtml::flex_item_row_direction::get_el_cross_size()
287 ////////////////////////////////////////////////////////////////////////////////////
289 void litehtml::flex_item_column_direction::direction_specific_init(const litehtml::containing_block_context
&self_size
,
290 litehtml::formatting_context
*fmt_ctx
)
292 if(el
->css().get_margins().top
.is_predefined())
294 auto_margin_main_start
= 0;
296 if(el
->css().get_margins().bottom
.is_predefined())
298 auto_margin_main_end
= 0;
300 if(el
->css().get_margins().left
.is_predefined())
302 auto_margin_cross_start
= true;
304 if(el
->css().get_margins().right
.is_predefined())
306 auto_margin_cross_end
= true;
308 if (el
->css().get_min_height().is_predefined())
310 el
->render(0, 0, self_size
.new_width(self_size
.render_width
, containing_block_context::size_mode_content
), fmt_ctx
);
311 min_size
= el
->height();
314 min_size
= el
->css().get_min_height().calc_percent(self_size
.height
) +
315 el
->content_offset_height();
317 if (!el
->css().get_max_height().is_predefined())
319 max_size
= el
->css().get_max_height().calc_percent(self_size
.height
) +
320 el
->content_offset_width();
323 bool flex_basis_predefined
= el
->css().get_flex_basis().is_predefined();
324 int predef
= flex_basis_auto
;
325 if(flex_basis_predefined
)
327 predef
= el
->css().get_flex_basis().predef();
330 if(el
->css().get_flex_basis().val() < 0)
332 flex_basis_predefined
= true;
336 if (flex_basis_predefined
)
340 case flex_basis_auto
:
341 if (!el
->css().get_height().is_predefined())
343 base_size
= el
->css().get_height().calc_percent(self_size
.height
) +
344 el
->content_offset_height();
347 case flex_basis_max_content
:
348 case flex_basis_fit_content
:
349 el
->render(0, 0, self_size
, fmt_ctx
);
350 base_size
= el
->height();
352 case flex_basis_min_content
:
353 base_size
= min_size
;
360 if(el
->css().get_flex_basis().units() == css_units_percentage
)
362 if(self_size
.height
.type
== containing_block_context::cbc_value_type_absolute
)
364 base_size
= el
->css().get_flex_basis().calc_percent(self_size
.height
) +
365 el
->content_offset_height();
372 base_size
= (int) el
->css().get_flex_basis().val() + el
->content_offset_height();
374 base_size
= std::max(base_size
, min_size
);
378 void litehtml::flex_item_column_direction::apply_main_auto_margins()
380 // apply auto margins to item
381 if(!auto_margin_main_start
.is_default())
383 el
->get_margins().top
= auto_margin_main_start
;
384 el
->pos().y
+= auto_margin_main_start
;
386 if(!auto_margin_main_end
.is_default()) el
->get_margins().bottom
= auto_margin_main_end
;
389 bool litehtml::flex_item_column_direction::apply_cross_auto_margins(int cross_size
)
391 if(auto_margin_cross_end
|| auto_margin_cross_start
)
394 if(auto_margin_cross_end
)
398 if(auto_margin_cross_start
)
402 int margin
= (cross_size
- el
->width()) / margins_num
;
403 if(auto_margin_cross_start
)
405 el
->get_margins().left
= margin
;
406 el
->pos().x
+= el
->content_offset_left();
408 if(auto_margin_cross_end
)
410 el
->get_margins().right
= margin
;
416 void litehtml::flex_item_column_direction::set_main_position(int pos
)
418 el
->pos().y
= pos
+ el
->content_offset_top();
421 void litehtml::flex_item_column_direction::set_cross_position(int pos
)
423 el
->pos().x
= pos
+ el
->content_offset_left();
426 void litehtml::flex_item_column_direction::align_stretch(flex_line
&ln
, const containing_block_context
&self_size
,
427 formatting_context
*fmt_ctx
)
431 if (!el
->css().get_width().is_predefined())
433 el
->render(ln
.cross_start
,
434 el
->pos().y
- el
->content_offset_top(),
435 self_size
.new_width_height(ln
.cross_size
- el
->content_offset_width() + el
->box_sizing_width(),
436 main_size
- el
->content_offset_height() + el
->box_sizing_height(),
437 containing_block_context::size_mode_exact_height
),
441 el
->render(ln
.cross_start
,
442 el
->pos().y
- el
->content_offset_top(),
443 self_size
.new_width_height(
444 ln
.cross_size
- el
->content_offset_width() + el
->box_sizing_width(),
445 main_size
- el
->content_offset_height() + el
->box_sizing_height(),
446 containing_block_context::size_mode_exact_width
|
447 containing_block_context::size_mode_exact_height
),
450 /// Apply auto margins after rendering
451 apply_main_auto_margins();
454 void litehtml::flex_item_column_direction::align_baseline(litehtml::flex_line
&ln
,
455 const containing_block_context
&self_size
,
456 formatting_context
*fmt_ctx
)
458 // The fallback alignment for first baseline is start, the one for last baseline is end.
459 if(align
& flex_align_items_last
)
463 set_cross_position(ln
.cross_start
);
466 set_cross_position(ln
.cross_start
+ ln
.cross_size
- get_el_cross_size());
470 if(!ln
.reverse_cross
)
472 set_cross_position(ln
.cross_start
);
475 set_cross_position(ln
.cross_start
+ ln
.cross_size
- get_el_cross_size());
480 int litehtml::flex_item_column_direction::get_el_main_size()
485 int litehtml::flex_item_column_direction::get_el_cross_size()