add support for Ayatana indicator to Notification plugin
[claws.git] / src / plugins / litehtml_viewer / litehtml / css_properties.cpp
bloba3b458ebfa9026842e9491c1bb28713df820b2bc
1 #include "html.h"
2 #include "css_properties.h"
3 #include <cmath>
5 #define offset(member) ((uint_ptr)&this->member - (uint_ptr)this)
7 void litehtml::css_properties::compute(const element* el, const document::ptr& doc)
9 compute_font(el, doc);
10 int font_size = get_font_size();
11 m_color = el->get_color_property(_color_, true, web_color::black, offset(m_color));
13 m_el_position = (element_position) el->get_enum_property( _position_, false, element_position_static, offset(m_el_position));
14 m_display = (style_display) el->get_enum_property( _display_, false, display_inline, offset(m_display));
15 m_visibility = (visibility) el->get_enum_property( _visibility_, true, visibility_visible, offset(m_visibility));
16 m_float = (element_float) el->get_enum_property( _float_, false, float_none, offset(m_float));
17 m_clear = (element_clear) el->get_enum_property( _clear_, false, clear_none, offset(m_clear));
18 m_box_sizing = (box_sizing) el->get_enum_property( _box_sizing_, false, box_sizing_content_box, offset(m_box_sizing));
19 m_overflow = (overflow) el->get_enum_property( _overflow_, false, overflow_visible, offset(m_overflow));
20 m_text_align = (text_align) el->get_enum_property( _text_align_, true, text_align_left, offset(m_text_align));
21 m_vertical_align = (vertical_align) el->get_enum_property( _vertical_align_, false, va_baseline, offset(m_vertical_align));
22 m_text_transform = (text_transform) el->get_enum_property( _text_transform_, true, text_transform_none, offset(m_text_transform));
23 m_white_space = (white_space) el->get_enum_property( _white_space_, true, white_space_normal, offset(m_white_space));
24 m_caption_side = (caption_side) el->get_enum_property( _caption_side_, true, caption_side_top, offset(m_caption_side));
26 // https://www.w3.org/TR/CSS22/visuren.html#dis-pos-flo
27 if (m_display == display_none)
29 // 1. If 'display' has the value 'none', then 'position' and 'float' do not apply. In this case, the element
30 // generates no box.
31 m_float = float_none;
32 } else
34 // 2. Otherwise, if 'position' has the value 'absolute' or 'fixed', the box is absolutely positioned,
35 // the computed value of 'float' is 'none', and display is set according to the table below.
36 // The position of the box will be determined by the 'top', 'right', 'bottom' and 'left' properties
37 // and the box's containing block.
38 if (m_el_position == element_position_absolute || m_el_position == element_position_fixed)
40 m_float = float_none;
42 if (m_display == display_inline_table)
44 m_display = display_table;
45 } else if (m_display == display_inline ||
46 m_display == display_table_row_group ||
47 m_display == display_table_column ||
48 m_display == display_table_column_group ||
49 m_display == display_table_header_group ||
50 m_display == display_table_footer_group ||
51 m_display == display_table_row ||
52 m_display == display_table_cell ||
53 m_display == display_table_caption ||
54 m_display == display_inline_block)
56 m_display = display_block;
58 } else if (m_float != float_none)
60 // 3. Otherwise, if 'float' has a value other than 'none', the box is floated and 'display' is set
61 // according to the table below.
62 if (m_display == display_inline_table)
64 m_display = display_table;
65 } else if (m_display == display_inline ||
66 m_display == display_table_row_group ||
67 m_display == display_table_column ||
68 m_display == display_table_column_group ||
69 m_display == display_table_header_group ||
70 m_display == display_table_footer_group ||
71 m_display == display_table_row ||
72 m_display == display_table_cell ||
73 m_display == display_table_caption ||
74 m_display == display_inline_block)
76 m_display = display_block;
78 } else if(el->is_root())
80 // 4. Otherwise, if the element is the root element, 'display' is set according to the table below,
81 // except that it is undefined in CSS 2.2 whether a specified value of 'list-item' becomes a
82 // computed value of 'block' or 'list-item'.
83 if (m_display == display_inline_table)
85 m_display = display_table;
86 } else if (m_display == display_inline ||
87 m_display == display_table_row_group ||
88 m_display == display_table_column ||
89 m_display == display_table_column_group ||
90 m_display == display_table_header_group ||
91 m_display == display_table_footer_group ||
92 m_display == display_table_row ||
93 m_display == display_table_cell ||
94 m_display == display_table_caption ||
95 m_display == display_inline_block ||
96 m_display == display_list_item)
98 m_display = display_block;
102 // 5. Otherwise, the remaining 'display' property values apply as specified.
104 const css_length _auto = css_length::predef_value(0);
105 const css_length none = _auto, normal = _auto;
107 m_css_width = el->get_length_property(_width_, false, _auto, offset(m_css_width));
108 m_css_height = el->get_length_property(_height_, false, _auto, offset(m_css_height));
110 m_css_min_width = el->get_length_property(_min_width_, false, _auto, offset(m_css_min_width));
111 m_css_min_height = el->get_length_property(_min_height_, false, _auto, offset(m_css_min_height));
113 m_css_max_width = el->get_length_property(_max_width_, false, none, offset(m_css_max_width));
114 m_css_max_height = el->get_length_property(_max_height_, false, none, offset(m_css_max_height));
116 doc->cvt_units(m_css_width, font_size);
117 doc->cvt_units(m_css_height, font_size);
119 doc->cvt_units(m_css_min_width, font_size);
120 doc->cvt_units(m_css_min_height, font_size);
122 doc->cvt_units(m_css_max_width, font_size);
123 doc->cvt_units(m_css_max_height, font_size);
125 m_css_margins.left = el->get_length_property(_margin_left_, false, 0, offset(m_css_margins.left));
126 m_css_margins.right = el->get_length_property(_margin_right_, false, 0, offset(m_css_margins.right));
127 m_css_margins.top = el->get_length_property(_margin_top_, false, 0, offset(m_css_margins.top));
128 m_css_margins.bottom = el->get_length_property(_margin_bottom_, false, 0, offset(m_css_margins.bottom));
130 doc->cvt_units(m_css_margins.left, font_size);
131 doc->cvt_units(m_css_margins.right, font_size);
132 doc->cvt_units(m_css_margins.top, font_size);
133 doc->cvt_units(m_css_margins.bottom, font_size);
135 m_css_padding.left = el->get_length_property(_padding_left_, false, 0, offset(m_css_padding.left));
136 m_css_padding.right = el->get_length_property(_padding_right_, false, 0, offset(m_css_padding.right));
137 m_css_padding.top = el->get_length_property(_padding_top_, false, 0, offset(m_css_padding.top));
138 m_css_padding.bottom = el->get_length_property(_padding_bottom_, false, 0, offset(m_css_padding.bottom));
140 doc->cvt_units(m_css_padding.left, font_size);
141 doc->cvt_units(m_css_padding.right, font_size);
142 doc->cvt_units(m_css_padding.top, font_size);
143 doc->cvt_units(m_css_padding.bottom, font_size);
145 m_css_borders.left.color = el->get_color_property(_border_left_color_, false, m_color, offset(m_css_borders.left.color));
146 m_css_borders.right.color = el->get_color_property(_border_right_color_, false, m_color, offset(m_css_borders.right.color));
147 m_css_borders.top.color = el->get_color_property(_border_top_color_, false, m_color, offset(m_css_borders.top.color));
148 m_css_borders.bottom.color = el->get_color_property(_border_bottom_color_, false, m_color, offset(m_css_borders.bottom.color));
150 m_css_borders.left.style = (border_style) el->get_enum_property(_border_left_style_, false, border_style_none, offset(m_css_borders.left.style));
151 m_css_borders.right.style = (border_style) el->get_enum_property(_border_right_style_, false, border_style_none, offset(m_css_borders.right.style));
152 m_css_borders.top.style = (border_style) el->get_enum_property(_border_top_style_, false, border_style_none, offset(m_css_borders.top.style));
153 m_css_borders.bottom.style = (border_style) el->get_enum_property(_border_bottom_style_, false, border_style_none, offset(m_css_borders.bottom.style));
155 m_css_borders.left.width = el->get_length_property(_border_left_width_, false, border_width_medium_value, offset(m_css_borders.left.width));
156 m_css_borders.right.width = el->get_length_property(_border_right_width_, false, border_width_medium_value, offset(m_css_borders.right.width));
157 m_css_borders.top.width = el->get_length_property(_border_top_width_, false, border_width_medium_value, offset(m_css_borders.top.width));
158 m_css_borders.bottom.width = el->get_length_property(_border_bottom_width_, false, border_width_medium_value, offset(m_css_borders.bottom.width));
160 if (m_css_borders.left.style == border_style_none || m_css_borders.left.style == border_style_hidden)
161 m_css_borders.left.width = 0;
162 if (m_css_borders.right.style == border_style_none || m_css_borders.right.style == border_style_hidden)
163 m_css_borders.right.width = 0;
164 if (m_css_borders.top.style == border_style_none || m_css_borders.top.style == border_style_hidden)
165 m_css_borders.top.width = 0;
166 if (m_css_borders.bottom.style == border_style_none || m_css_borders.bottom.style == border_style_hidden)
167 m_css_borders.bottom.width = 0;
169 doc->cvt_units(m_css_borders.left.width, font_size);
170 doc->cvt_units(m_css_borders.right.width, font_size);
171 doc->cvt_units(m_css_borders.top.width, font_size);
172 doc->cvt_units(m_css_borders.bottom.width, font_size);
174 m_css_borders.radius.top_left_x = el->get_length_property(_border_top_left_radius_x_, false, 0, offset(m_css_borders.radius.top_left_x));
175 m_css_borders.radius.top_left_y = el->get_length_property(_border_top_left_radius_y_, false, 0, offset(m_css_borders.radius.top_left_y));
177 m_css_borders.radius.top_right_x = el->get_length_property(_border_top_right_radius_x_, false, 0, offset(m_css_borders.radius.top_right_x));
178 m_css_borders.radius.top_right_y = el->get_length_property(_border_top_right_radius_y_, false, 0, offset(m_css_borders.radius.top_right_y));
180 m_css_borders.radius.bottom_left_x = el->get_length_property(_border_bottom_left_radius_x_, false, 0, offset(m_css_borders.radius.bottom_left_x));
181 m_css_borders.radius.bottom_left_y = el->get_length_property(_border_bottom_left_radius_y_, false, 0, offset(m_css_borders.radius.bottom_left_y));
183 m_css_borders.radius.bottom_right_x = el->get_length_property(_border_bottom_right_radius_x_, false, 0, offset(m_css_borders.radius.bottom_right_x));
184 m_css_borders.radius.bottom_right_y = el->get_length_property(_border_bottom_right_radius_y_, false, 0, offset(m_css_borders.radius.bottom_right_y));
186 doc->cvt_units( m_css_borders.radius.top_left_x, font_size);
187 doc->cvt_units( m_css_borders.radius.top_left_y, font_size);
188 doc->cvt_units( m_css_borders.radius.top_right_x, font_size);
189 doc->cvt_units( m_css_borders.radius.top_right_y, font_size);
190 doc->cvt_units( m_css_borders.radius.bottom_left_x, font_size);
191 doc->cvt_units( m_css_borders.radius.bottom_left_y, font_size);
192 doc->cvt_units( m_css_borders.radius.bottom_right_x, font_size);
193 doc->cvt_units( m_css_borders.radius.bottom_right_y, font_size);
195 m_border_collapse = (border_collapse) el->get_enum_property(_border_collapse_, true, border_collapse_separate, offset(m_border_collapse));
197 m_css_border_spacing_x = el->get_length_property(__litehtml_border_spacing_x_, true, 0, offset(m_css_border_spacing_x));
198 m_css_border_spacing_y = el->get_length_property(__litehtml_border_spacing_y_, true, 0, offset(m_css_border_spacing_y));
200 doc->cvt_units(m_css_border_spacing_x, font_size);
201 doc->cvt_units(m_css_border_spacing_y, font_size);
203 m_css_offsets.left = el->get_length_property(_left_, false, _auto, offset(m_css_offsets.left));
204 m_css_offsets.right = el->get_length_property(_right_, false, _auto, offset(m_css_offsets.right));
205 m_css_offsets.top = el->get_length_property(_top_, false, _auto, offset(m_css_offsets.top));
206 m_css_offsets.bottom = el->get_length_property(_bottom_,false, _auto, offset(m_css_offsets.bottom));
208 doc->cvt_units(m_css_offsets.left, font_size);
209 doc->cvt_units(m_css_offsets.right, font_size);
210 doc->cvt_units(m_css_offsets.top, font_size);
211 doc->cvt_units(m_css_offsets.bottom, font_size);
213 m_z_index = el->get_length_property(_z_index_, false, _auto, offset(m_z_index));
214 m_content = el->get_string_property(_content_, false, "", offset(m_content));
215 m_cursor = el->get_string_property(_cursor_, true, "auto", offset(m_cursor));
217 m_css_text_indent = el->get_length_property(_text_indent_, true, 0, offset(m_css_text_indent));
218 doc->cvt_units(m_css_text_indent, font_size);
220 m_css_line_height = el->get_length_property(_line_height_, true, normal, offset(m_css_line_height));
221 if(m_css_line_height.is_predefined())
223 m_line_height = m_font_metrics.height;
224 } else if(m_css_line_height.units() == css_units_none)
226 m_line_height = (int) std::nearbyint(m_css_line_height.val() * font_size);
227 } else
229 m_line_height = doc->to_pixels(m_css_line_height, font_size, font_size);
230 m_css_line_height = (float) m_line_height;
233 m_list_style_type = (list_style_type) el->get_enum_property(_list_style_type_, true, list_style_type_disc, offset(m_list_style_type));
234 m_list_style_position = (list_style_position) el->get_enum_property(_list_style_position_, true, list_style_position_outside, offset(m_list_style_position));
236 m_list_style_image = el->get_string_property(_list_style_image_, true, "", offset(m_list_style_image));
237 if (!m_list_style_image.empty())
239 m_list_style_image_baseurl = el->get_string_property(_list_style_image_baseurl_, true, "", offset(m_list_style_image_baseurl));
240 doc->container()->load_image(m_list_style_image.c_str(), m_list_style_image_baseurl.c_str(), true);
243 m_order = el->get_int_property(_order_, false, 0, offset(m_order));
245 compute_background(el, doc);
246 compute_flex(el, doc);
249 static const int font_size_table[8][7] =
251 { 9, 9, 9, 9, 11, 14, 18},
252 { 9, 9, 9, 10, 12, 15, 20},
253 { 9, 9, 9, 11, 13, 17, 22},
254 { 9, 9, 10, 12, 14, 18, 24},
255 { 9, 9, 10, 13, 16, 20, 26},
256 { 9, 9, 11, 14, 17, 21, 28},
257 { 9, 10, 12, 15, 17, 23, 30},
258 { 9, 10, 13, 16, 18, 24, 32}
261 void litehtml::css_properties::compute_font(const element* el, const document::ptr& doc)
263 // initialize font size
264 css_length sz = el->get_length_property(_font_size_, true, css_length::predef_value(font_size_medium), offset(m_font_size));
266 int parent_sz = 0;
267 int doc_font_size = doc->container()->get_default_font_size();
268 element::ptr el_parent = el->parent();
269 if (el_parent)
271 parent_sz = el_parent->css().get_font_size();
272 } else
274 parent_sz = doc_font_size;
277 int font_size = parent_sz;
279 if(sz.is_predefined())
281 int idx_in_table = doc_font_size - 9;
282 if(idx_in_table >= 0 && idx_in_table <= 7)
284 if(sz.predef() >= font_size_xx_small && sz.predef() <= font_size_xx_large)
286 font_size = font_size_table[idx_in_table][sz.predef()];
287 } else if(sz.predef() == font_size_smaller)
289 font_size = (int) (parent_sz / 1.2);
290 } else if(sz.predef() == font_size_larger)
292 font_size = (int) (parent_sz * 1.2);
293 } else
295 font_size = parent_sz;
297 } else
299 switch(sz.predef())
301 case font_size_xx_small:
302 font_size = doc_font_size * 3 / 5;
303 break;
304 case font_size_x_small:
305 font_size = doc_font_size * 3 / 4;
306 break;
307 case font_size_small:
308 font_size = doc_font_size * 8 / 9;
309 break;
310 case font_size_large:
311 font_size = doc_font_size * 6 / 5;
312 break;
313 case font_size_x_large:
314 font_size = doc_font_size * 3 / 2;
315 break;
316 case font_size_xx_large:
317 font_size = doc_font_size * 2;
318 break;
319 case font_size_smaller:
320 font_size = (int) (parent_sz / 1.2);
321 break;
322 case font_size_larger:
323 font_size = (int) (parent_sz * 1.2);
324 break;
325 default:
326 font_size = parent_sz;
327 break;
330 } else
332 if(sz.units() == css_units_percentage)
334 font_size = sz.calc_percent(parent_sz);
335 } else
337 font_size = doc->to_pixels(sz, parent_sz);
341 m_font_size = (float)font_size;
343 // initialize font
344 m_font_family = el->get_string_property(_font_family_, true, doc->container()->get_default_font_name(), offset(m_font_family));
345 m_font_weight = (font_weight) el->get_enum_property( _font_weight_, true, font_weight_normal, offset(m_font_weight));
346 m_font_style = (font_style) el->get_enum_property( _font_style_, true, font_style_normal, offset(m_font_style));
347 m_text_decoration = el->get_string_property(_text_decoration_, true, "none", offset(m_text_decoration));
349 m_font = doc->get_font(
350 m_font_family.c_str(),
351 font_size,
352 index_value(m_font_weight, font_weight_strings).c_str(),
353 index_value(m_font_style, font_style_strings).c_str(),
354 m_text_decoration.c_str(),
355 &m_font_metrics);
358 void litehtml::css_properties::compute_background(const element* el, const document::ptr& doc)
360 int font_size = get_font_size();
362 m_bg.m_color = el->get_color_property(_background_color_, false, web_color::transparent, offset(m_bg.m_color));
364 const css_size auto_auto(css_length::predef_value(background_size_auto), css_length::predef_value(background_size_auto));
365 m_bg.m_position_x = el->get_length_vector_property(_background_position_x_, false, { css_length(0, css_units_percentage) }, offset(m_bg.m_position_x));
366 m_bg.m_position_y = el->get_length_vector_property(_background_position_y_, false, { css_length(0, css_units_percentage) }, offset(m_bg.m_position_y));
367 m_bg.m_size = el->get_size_vector_property (_background_size_, false, { auto_auto }, offset(m_bg.m_size));
369 for (auto& x : m_bg.m_position_x) doc->cvt_units(x, font_size);
370 for (auto& y : m_bg.m_position_y) doc->cvt_units(y, font_size);
371 for (auto& size : m_bg.m_size)
373 doc->cvt_units(size.width, font_size);
374 doc->cvt_units(size.height, font_size);
377 m_bg.m_attachment = el->get_int_vector_property(_background_attachment_, false, { background_attachment_scroll }, offset(m_bg.m_attachment));
378 m_bg.m_repeat = el->get_int_vector_property(_background_repeat_, false, { background_repeat_repeat }, offset(m_bg.m_repeat));
379 m_bg.m_clip = el->get_int_vector_property(_background_clip_, false, { background_box_border }, offset(m_bg.m_clip));
380 m_bg.m_origin = el->get_int_vector_property(_background_origin_, false, { background_box_padding }, offset(m_bg.m_origin));
382 m_bg.m_image = el->get_string_vector_property(_background_image_, false, {""}, offset(m_bg.m_image));
383 m_bg.m_baseurl = el->get_string_property(_background_image_baseurl_, false, "", offset(m_bg.m_baseurl));
385 for (const auto& image : m_bg.m_image)
387 if (!image.empty())
389 doc->container()->load_image(image.c_str(), m_bg.m_baseurl.c_str(), true);
394 void litehtml::css_properties::compute_flex(const element* el, const document::ptr& doc)
396 if (m_display == display_flex || m_display == display_inline_flex)
398 m_flex_direction = (flex_direction) el->get_enum_property(_flex_direction_, false, flex_direction_row, offset(m_flex_direction));
399 m_flex_wrap = (flex_wrap) el->get_enum_property(_flex_wrap_, false, flex_wrap_nowrap, offset(m_flex_wrap));
401 m_flex_justify_content = (flex_justify_content) el->get_enum_property(_justify_content_, false, flex_justify_content_flex_start, offset(m_flex_justify_content));
402 m_flex_align_items = (flex_align_items) el->get_enum_property(_align_items_, false, flex_align_items_flex_normal, offset(m_flex_align_items));
403 m_flex_align_content = (flex_align_content) el->get_enum_property(_align_content_, false, flex_align_content_stretch, offset(m_flex_align_content));
405 m_flex_align_self = (flex_align_items) el->get_enum_property(_align_self_, false, flex_align_items_auto, offset(m_flex_align_self));
406 auto parent = el->parent();
407 if (parent && (parent->css().m_display == display_flex || parent->css().m_display == display_inline_flex))
409 m_flex_grow = el->get_number_property(_flex_grow_, false, 0, offset(m_flex_grow));
410 m_flex_shrink = el->get_number_property(_flex_shrink_, false, 1, offset(m_flex_shrink));
411 m_flex_basis = el->get_length_property(_flex_basis_, false, css_length::predef_value(flex_basis_auto), offset(m_flex_basis));
412 if(!m_flex_basis.is_predefined() && m_flex_basis.units() == css_units_none && m_flex_basis.val() != 0)
414 // flex-basis property must contain units
415 m_flex_basis.predef(flex_basis_auto);
417 doc->cvt_units(m_flex_basis, get_font_size());
418 if(m_display == display_inline || m_display == display_inline_block)
420 m_display = display_block;
421 } else if(m_display == display_inline_table)
423 m_display = display_table;
424 } else if(m_display == display_inline_flex)
426 m_display = display_flex;
431 std::vector<std::tuple<litehtml::string, litehtml::string>> litehtml::css_properties::dump_get_attrs()
433 std::vector<std::tuple<string, string>> ret;
435 ret.emplace_back(std::make_tuple("display", index_value(m_display, style_display_strings)));
436 ret.emplace_back(std::make_tuple("el_position", index_value(m_el_position, element_position_strings)));
437 ret.emplace_back(std::make_tuple("text_align", index_value(m_text_align, text_align_strings)));
438 ret.emplace_back(std::make_tuple("font_size", m_font_size.to_string()));
439 ret.emplace_back(std::make_tuple("overflow", index_value(m_overflow, overflow_strings)));
440 ret.emplace_back(std::make_tuple("white_space", index_value(m_white_space, white_space_strings)));
441 ret.emplace_back(std::make_tuple("visibility", index_value(m_visibility, visibility_strings)));
442 ret.emplace_back(std::make_tuple("box_sizing", index_value(m_box_sizing, box_sizing_strings)));
443 ret.emplace_back(std::make_tuple("z_index", m_z_index.to_string()));
444 ret.emplace_back(std::make_tuple("vertical_align", index_value(m_vertical_align, vertical_align_strings)));
445 ret.emplace_back(std::make_tuple("float", index_value(m_float, element_float_strings)));
446 ret.emplace_back(std::make_tuple("clear", index_value(m_clear, element_clear_strings)));
447 ret.emplace_back(std::make_tuple("margins", m_css_margins.to_string()));
448 ret.emplace_back(std::make_tuple("padding", m_css_padding.to_string()));
449 ret.emplace_back(std::make_tuple("borders", m_css_borders.to_string()));
450 ret.emplace_back(std::make_tuple("width", m_css_width.to_string()));
451 ret.emplace_back(std::make_tuple("height", m_css_height.to_string()));
452 ret.emplace_back(std::make_tuple("min_width", m_css_min_width.to_string()));
453 ret.emplace_back(std::make_tuple("min_height", m_css_min_width.to_string()));
454 ret.emplace_back(std::make_tuple("max_width", m_css_max_width.to_string()));
455 ret.emplace_back(std::make_tuple("max_height", m_css_max_width.to_string()));
456 ret.emplace_back(std::make_tuple("offsets", m_css_offsets.to_string()));
457 ret.emplace_back(std::make_tuple("text_indent", m_css_text_indent.to_string()));
458 ret.emplace_back(std::make_tuple("line_height", std::to_string(m_line_height)));
459 ret.emplace_back(std::make_tuple("list_style_type", index_value(m_list_style_type, list_style_type_strings)));
460 ret.emplace_back(std::make_tuple("list_style_position", index_value(m_list_style_position, list_style_position_strings)));
461 ret.emplace_back(std::make_tuple("border_spacing_x", m_css_border_spacing_x.to_string()));
462 ret.emplace_back(std::make_tuple("border_spacing_y", m_css_border_spacing_y.to_string()));
464 return ret;