add support for Ayatana indicator to Notification plugin
[claws.git] / src / plugins / litehtml_viewer / litehtml / flex_item.cpp
blobd0fbaecd7779c44c64b07b63c404e3b5cbb2bcad
1 #include "html.h"
2 #include "flex_item.h"
3 #include "render_item.h"
4 #include "flex_line.h"
5 #include <cmath>
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)
27 align = align_items;
28 } else
30 align = el->css().get_flex_align_self();
32 main_size = base_size;
33 scaled_flex_shrink_factor = base_size * shrink;
34 frozen = false;
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))
45 switch (align & 0xFF)
47 case flex_align_items_baseline:
48 align_baseline(ln, self_size, fmt_ctx);
49 break;
50 case flex_align_items_flex_end:
51 if(ln.reverse_cross)
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());
58 break;
59 case flex_align_items_center:
60 set_cross_position(ln.cross_start + ln.cross_size / 2 - get_el_cross_size() / 2);
61 break;
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());
66 break;
68 case flex_align_items_start:
69 set_cross_position(ln.cross_start);
70 break;
71 default:
72 align_stretch(ln, self_size, fmt_ctx);
73 break;
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();
87 return 0;
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();
99 return 0;
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;
131 } else
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();
146 } else
148 if(el->css().get_flex_basis().val() < 0)
150 flex_basis_predefined = true;
154 if (flex_basis_predefined)
156 switch (predef)
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();
163 break;
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),
171 fmt_ctx);
172 break;
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),
179 fmt_ctx);
181 base_size = content_size;
182 break;
183 case flex_basis_max_content:
184 el->render(0, 0, self_size, fmt_ctx);
185 base_size = el->width();
186 break;
187 default:
188 base_size = 0;
189 break;
191 } else
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)
214 int margins_num = 0;
215 if(auto_margin_cross_end)
217 margins_num++;
219 if(auto_margin_cross_start)
221 margins_num++;
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;
233 return true;
235 return false;
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
259 ), fmt_ctx);
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());
271 } else
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()
279 return el->width();
282 int litehtml::flex_item_row_direction::get_el_cross_size()
284 return el->height();
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();
312 } else
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();
328 } else
330 if(el->css().get_flex_basis().val() < 0)
332 flex_basis_predefined = true;
336 if (flex_basis_predefined)
338 switch (predef)
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();
345 break;
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();
351 break;
352 case flex_basis_min_content:
353 base_size = min_size;
354 break;
355 default:
356 base_size = 0;
358 } else
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();
366 } else
368 base_size = 0;
370 } else
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)
393 int margins_num = 0;
394 if(auto_margin_cross_end)
396 margins_num++;
398 if(auto_margin_cross_start)
400 margins_num++;
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;
413 return false;
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)
429 /// MAIN: Y
430 /// CROSS: X
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),
438 fmt_ctx, false);
439 } else
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),
448 fmt_ctx, false);
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)
461 if(ln.reverse_cross)
463 set_cross_position(ln.cross_start);
464 } else
466 set_cross_position(ln.cross_start + ln.cross_size - get_el_cross_size());
468 } else
470 if(!ln.reverse_cross)
472 set_cross_position(ln.cross_start);
473 } else
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()
482 return el->height();
485 int litehtml::flex_item_column_direction::get_el_cross_size()
487 return el->width();