add support for Ayatana indicator to Notification plugin
[claws.git] / src / plugins / litehtml_viewer / litehtml / style.cpp
blob356f49afcd931fb5025757304bd8d77a4c21ffd5
1 #include "html.h"
2 #include "style.h"
4 namespace litehtml
7 std::map<string_id, string> style::m_valid_values =
9 { _display_, style_display_strings },
10 { _visibility_, visibility_strings },
11 { _position_, element_position_strings },
12 { _float_, element_float_strings },
13 { _clear_, element_clear_strings },
14 { _overflow_, overflow_strings },
15 { _box_sizing_, box_sizing_strings },
17 { _text_align_, text_align_strings },
18 { _vertical_align_, vertical_align_strings },
19 { _text_transform_, text_transform_strings },
20 { _white_space_, white_space_strings },
22 { _font_style_, font_style_strings },
23 { _font_variant_, font_variant_strings },
24 { _font_weight_, font_weight_strings },
26 { _list_style_type_, list_style_type_strings },
27 { _list_style_position_, list_style_position_strings },
29 { _border_left_style_, border_style_strings },
30 { _border_right_style_, border_style_strings },
31 { _border_top_style_, border_style_strings },
32 { _border_bottom_style_, border_style_strings },
33 { _border_collapse_, border_collapse_strings },
35 // these 4 properties are comma-separated lists of keywords, see parse_keyword_comma_list
36 { _background_attachment_, background_attachment_strings },
37 { _background_repeat_, background_repeat_strings },
38 { _background_clip_, background_box_strings },
39 { _background_origin_, background_box_strings },
41 { _flex_direction_, flex_direction_strings },
42 { _flex_wrap_, flex_wrap_strings },
43 { _justify_content_, flex_justify_content_strings },
44 { _align_items_, flex_align_items_strings },
45 { _align_content_, flex_align_content_strings },
46 { _align_self_, flex_align_items_strings },
48 { _caption_side_, caption_side_strings },
51 void style::parse(const string& txt, const string& baseurl, document_container* container)
53 std::vector<string> properties;
54 split_string(txt, properties, ";", "", "\"'");
56 for(const auto & property : properties)
58 parse_property(property, baseurl, container);
62 void style::parse_property(const string& txt, const string& baseurl, document_container* container)
64 string::size_type pos = txt.find_first_of(':');
65 if(pos != string::npos)
67 string name = txt.substr(0, pos);
68 string val = txt.substr(pos + 1);
70 trim(name); lcase(name);
71 trim(val);
73 if(!name.empty() && !val.empty())
75 string_vector vals;
76 split_string(val, vals, "!");
77 if(vals.size() == 1)
79 add_property(_id(name), val, baseurl, false, container);
80 } else if(vals.size() > 1)
82 trim(vals[0]);
83 lcase(vals[1]);
84 add_property(_id(name), vals[0], baseurl, vals[1] == "important", container);
90 void style::add_property(string_id name, const string& val, const string& baseurl, bool important, document_container* container)
92 if (val.find("var(") != -1) return add_parsed_property(name, property_value(val, important, prop_type_var));
93 if (val == "inherit" && name != _font_) return add_parsed_property(name, property_value(important, prop_type_inherit));
95 int idx;
96 string url;
97 css_length len[4], length;
99 switch (name)
101 // keyword-only properties
102 case _display_:
103 case _visibility_:
104 case _position_:
105 case _float_:
106 case _clear_:
107 case _box_sizing_:
108 case _overflow_:
110 case _text_align_:
111 case _vertical_align_:
112 case _text_transform_:
113 case _white_space_:
115 case _font_style_:
116 case _font_variant_:
117 case _font_weight_:
119 case _list_style_type_:
120 case _list_style_position_:
122 case _border_top_style_:
123 case _border_bottom_style_:
124 case _border_left_style_:
125 case _border_right_style_:
126 case _border_collapse_:
128 case _flex_direction_:
129 case _flex_wrap_:
130 case _justify_content_:
131 case _align_content_:
133 case _caption_side_:
135 idx = value_index(val, m_valid_values[name]);
136 if (idx >= 0)
138 add_parsed_property(name, property_value(idx, important));
140 break;
142 case _align_items_:
143 case _align_self_:
144 parse_align_self(name, val, important);
145 break;
147 // <length>
148 case _text_indent_:
149 case _padding_left_:
150 case _padding_right_:
151 case _padding_top_:
152 case _padding_bottom_:
153 length.fromString(val);
154 add_parsed_property(name, property_value(length, important));
155 break;
157 // <length> | auto
158 case _left_:
159 case _right_:
160 case _top_:
161 case _bottom_:
162 case _z_index_: // <integer> | auto
163 case _width_:
164 case _height_:
165 case _min_width_:
166 case _min_height_:
167 case _margin_left_:
168 case _margin_right_:
169 case _margin_top_:
170 case _margin_bottom_:
171 length.fromString(val, "auto", -1);
172 add_parsed_property(name, property_value(length, important));
173 break;
175 // <length> | none
176 case _max_width_:
177 case _max_height_:
178 length.fromString(val, "none", -1);
179 add_parsed_property(name, property_value(length, important));
180 break;
182 case _line_height_:
183 length.fromString(val, "normal", -1);
184 add_parsed_property(name, property_value(length, important));
185 break;
187 case _font_size_:
188 length.fromString(val, font_size_strings, -1);
189 add_parsed_property(name, property_value(length, important));
190 break;
192 // Parse background shorthand properties
193 case _background_:
194 parse_background(val, baseurl, important, container);
195 break;
197 case _background_image_:
198 parse_background_image(val, baseurl, important);
199 break;
201 case _background_attachment_:
202 case _background_repeat_:
203 case _background_clip_:
204 case _background_origin_:
205 parse_keyword_comma_list(name, val, important);
206 break;
208 case _background_position_:
209 parse_background_position(val, important);
210 break;
212 case _background_size_:
213 parse_background_size(val, important);
214 break;
216 // Parse border spacing properties
217 case _border_spacing_:
218 parse_two_lengths(val, len);
219 add_parsed_property(__litehtml_border_spacing_x_, property_value(len[0], important));
220 add_parsed_property(__litehtml_border_spacing_y_, property_value(len[1], important));
221 break;
223 // Parse borders shorthand properties
224 case _border_:
226 string_vector tokens;
227 split_string(val, tokens, " ", "", "(");
228 for (const auto& token : tokens)
230 int idx = value_index(token, border_style_strings);
231 if (idx >= 0)
233 property_value style(idx, important);
234 add_parsed_property(_border_left_style_, style);
235 add_parsed_property(_border_right_style_, style);
236 add_parsed_property(_border_top_style_, style);
237 add_parsed_property(_border_bottom_style_, style);
239 else if (t_isdigit(token[0]) || token[0] == '.' ||
240 value_in_list(token, border_width_strings))
242 property_value width(parse_border_width(token), important);
243 add_parsed_property(_border_left_width_, width);
244 add_parsed_property(_border_right_width_, width);
245 add_parsed_property(_border_top_width_, width);
246 add_parsed_property(_border_bottom_width_, width);
248 else if (web_color::is_color(token, container))
250 web_color _color = web_color::from_string(token, container);
251 property_value color(_color, important);
252 add_parsed_property(_border_left_color_, color);
253 add_parsed_property(_border_right_color_, color);
254 add_parsed_property(_border_top_color_, color);
255 add_parsed_property(_border_bottom_color_, color);
258 break;
261 case _border_left_:
262 case _border_right_:
263 case _border_top_:
264 case _border_bottom_:
266 string_vector tokens;
267 split_string(val, tokens, " ", "", "(");
268 for (const auto& token : tokens)
270 int idx = value_index(token, border_style_strings);
271 if (idx >= 0)
273 add_parsed_property(_id(_s(name) + "-style"), property_value(idx, important));
275 else if (t_isdigit(token[0]) || token[0] == '.' ||
276 value_in_list(token, border_width_strings))
278 property_value width(parse_border_width(token), important);
279 add_parsed_property(_id(_s(name) + "-width"), width);
281 else if (web_color::is_color(token, container))
283 web_color color = web_color::from_string(token, container);
284 add_parsed_property(_id(_s(name) + "-color"), property_value(color, important));
287 break;
290 // Parse border-width/style/color shorthand properties
291 case _border_width_:
292 case _border_style_:
293 case _border_color_:
295 string prop = name == _border_width_ ? "-width" : name == _border_style_ ? "-style" : "-color";
297 string_vector tokens;
298 split_string(val, tokens, " ");
299 if (tokens.size() == 4)
301 add_property(_id("border-top" + prop), tokens[0], baseurl, important, container);
302 add_property(_id("border-right" + prop), tokens[1], baseurl, important, container);
303 add_property(_id("border-bottom" + prop), tokens[2], baseurl, important, container);
304 add_property(_id("border-left" + prop), tokens[3], baseurl, important, container);
306 else if (tokens.size() == 3)
308 add_property(_id("border-top" + prop), tokens[0], baseurl, important, container);
309 add_property(_id("border-right" + prop), tokens[1], baseurl, important, container);
310 add_property(_id("border-left" + prop), tokens[1], baseurl, important, container);
311 add_property(_id("border-bottom" + prop), tokens[2], baseurl, important, container);
313 else if (tokens.size() == 2)
315 add_property(_id("border-top" + prop), tokens[0], baseurl, important, container);
316 add_property(_id("border-bottom" + prop), tokens[0], baseurl, important, container);
317 add_property(_id("border-right" + prop), tokens[1], baseurl, important, container);
318 add_property(_id("border-left" + prop), tokens[1], baseurl, important, container);
320 else if (tokens.size() == 1)
322 add_property(_id("border-top" + prop), tokens[0], baseurl, important, container);
323 add_property(_id("border-bottom" + prop), tokens[0], baseurl, important, container);
324 add_property(_id("border-right" + prop), tokens[0], baseurl, important, container);
325 add_property(_id("border-left" + prop), tokens[0], baseurl, important, container);
327 break;
330 case _border_top_width_:
331 case _border_bottom_width_:
332 case _border_left_width_:
333 case _border_right_width_:
334 length = parse_border_width(val);
335 add_parsed_property(name, property_value(length, important));
336 break;
338 case _color_:
339 case _background_color_:
340 case _border_top_color_:
341 case _border_bottom_color_:
342 case _border_left_color_:
343 case _border_right_color_:
344 if (web_color::is_color(val, container))
346 web_color color = web_color::from_string(val, container);
347 add_parsed_property(name, property_value(color, important));
349 break;
351 // Parse border radius shorthand properties
352 case _border_bottom_left_radius_:
353 case _border_bottom_right_radius_:
354 case _border_top_right_radius_:
355 case _border_top_left_radius_:
356 parse_two_lengths(val, len);
357 add_parsed_property(_id(_s(name) + "-x"), property_value(len[0], important));
358 add_parsed_property(_id(_s(name) + "-y"), property_value(len[1], important));
359 break;
361 // Parse border-radius shorthand properties
362 case _border_radius_:
364 string_vector tokens;
365 split_string(val, tokens, "/");
366 if (tokens.size() == 1)
368 add_property(_border_radius_x_, tokens[0], baseurl, important, container);
369 add_property(_border_radius_y_, tokens[0], baseurl, important, container);
371 else if (tokens.size() >= 2)
373 add_property(_border_radius_x_, tokens[0], baseurl, important, container);
374 add_property(_border_radius_y_, tokens[1], baseurl, important, container);
376 break;
378 case _border_radius_x_:
379 case _border_radius_y_:
381 string_id top_left, top_right, bottom_right, bottom_left;
382 if (name == _border_radius_x_)
384 top_left = _border_top_left_radius_x_;
385 top_right = _border_top_right_radius_x_;
386 bottom_right = _border_bottom_right_radius_x_;
387 bottom_left = _border_bottom_left_radius_x_;
389 else
391 top_left = _border_top_left_radius_y_;
392 top_right = _border_top_right_radius_y_;
393 bottom_right = _border_bottom_right_radius_y_;
394 bottom_left = _border_bottom_left_radius_y_;
397 switch (parse_four_lengths(val, len))
399 case 1:
400 add_parsed_property(top_left, property_value(len[0], important));
401 add_parsed_property(top_right, property_value(len[0], important));
402 add_parsed_property(bottom_right, property_value(len[0], important));
403 add_parsed_property(bottom_left, property_value(len[0], important));
404 break;
405 case 2:
406 add_parsed_property(top_left, property_value(len[0], important));
407 add_parsed_property(top_right, property_value(len[1], important));
408 add_parsed_property(bottom_right, property_value(len[0], important));
409 add_parsed_property(bottom_left, property_value(len[1], important));
410 break;
411 case 3:
412 add_parsed_property(top_left, property_value(len[0], important));
413 add_parsed_property(top_right, property_value(len[1], important));
414 add_parsed_property(bottom_right, property_value(len[2], important));
415 add_parsed_property(bottom_left, property_value(len[1], important));
416 break;
417 case 4:
418 add_parsed_property(top_left, property_value(len[0], important));
419 add_parsed_property(top_right, property_value(len[1], important));
420 add_parsed_property(bottom_right, property_value(len[2], important));
421 add_parsed_property(bottom_left, property_value(len[3], important));
422 break;
424 break;
427 // Parse list-style shorthand properties
428 case _list_style_:
430 add_parsed_property(_list_style_type_, property_value(list_style_type_disc, important));
431 add_parsed_property(_list_style_position_, property_value(list_style_position_outside, important));
432 add_parsed_property(_list_style_image_, property_value("", important));
433 add_parsed_property(_list_style_image_baseurl_, property_value("", important));
435 string_vector tokens;
436 split_string(val, tokens, " ", "", "(");
437 for (const auto& token : tokens)
439 int idx = value_index(token, list_style_type_strings);
440 if (idx >= 0)
442 add_parsed_property(_list_style_type_, property_value(idx, important));
444 else
446 idx = value_index(token, list_style_position_strings);
447 if (idx >= 0)
449 add_parsed_property(_list_style_position_, property_value(idx, important));
451 else if (!strncmp(token.c_str(), "url", 3))
453 css::parse_css_url(token, url);
454 add_parsed_property(_list_style_image_, property_value(url, important));
455 add_parsed_property(_list_style_image_baseurl_, property_value(baseurl, important));
459 break;
462 case _list_style_image_:
463 css::parse_css_url(val, url);
464 add_parsed_property(_list_style_image_, property_value(url, important));
465 add_parsed_property(_list_style_image_baseurl_, property_value(baseurl, important));
466 break;
468 // Parse margin and padding shorthand properties
469 case _margin_:
470 case _padding_:
472 switch (parse_four_lengths(val, len))
474 case 4:
475 add_parsed_property(_id(_s(name) + "-top"), property_value(len[0], important));
476 add_parsed_property(_id(_s(name) + "-right"), property_value(len[1], important));
477 add_parsed_property(_id(_s(name) + "-bottom"), property_value(len[2], important));
478 add_parsed_property(_id(_s(name) + "-left"), property_value(len[3], important));
479 break;
480 case 3:
481 add_parsed_property(_id(_s(name) + "-top"), property_value(len[0], important));
482 add_parsed_property(_id(_s(name) + "-right"), property_value(len[1], important));
483 add_parsed_property(_id(_s(name) + "-left"), property_value(len[1], important));
484 add_parsed_property(_id(_s(name) + "-bottom"), property_value(len[2], important));
485 break;
486 case 2:
487 add_parsed_property(_id(_s(name) + "-top"), property_value(len[0], important));
488 add_parsed_property(_id(_s(name) + "-bottom"), property_value(len[0], important));
489 add_parsed_property(_id(_s(name) + "-right"), property_value(len[1], important));
490 add_parsed_property(_id(_s(name) + "-left"), property_value(len[1], important));
491 break;
492 case 1:
493 add_parsed_property(_id(_s(name) + "-top"), property_value(len[0], important));
494 add_parsed_property(_id(_s(name) + "-bottom"), property_value(len[0], important));
495 add_parsed_property(_id(_s(name) + "-right"), property_value(len[0], important));
496 add_parsed_property(_id(_s(name) + "-left"), property_value(len[0], important));
497 break;
499 break;
502 // Parse font shorthand properties
503 case _font_:
504 parse_font(val, important);
505 break;
507 // Parse flex-flow shorthand properties
508 case _flex_flow_:
510 string_vector tokens;
511 split_string(val, tokens, " ");
512 for (const auto& tok : tokens)
514 int idx;
515 if ((idx = value_index(tok, flex_direction_strings)) >= 0)
517 add_parsed_property(_flex_direction_, property_value(idx, important));
519 else if ((idx = value_index(tok, flex_wrap_strings)) >= 0)
521 add_parsed_property(_flex_wrap_, property_value(idx, important));
524 break;
527 // Parse flex shorthand properties
528 case _flex_:
529 parse_flex(val, important);
530 break;
532 case _flex_grow_:
533 case _flex_shrink_:
534 add_parsed_property(name, property_value(t_strtof(val), important));
535 break;
537 case _flex_basis_:
538 length.fromString(val, flex_basis_strings, -1);
539 add_parsed_property(_flex_basis_, property_value(length, important));
540 break;
542 case _order_: // <integer>
544 char* end;
545 int int_val = (int) strtol(val.c_str(), &end, 10);
546 if(end[0] == '\0')
548 add_parsed_property(name, property_value(int_val, important));
551 break;
552 case _counter_increment_:
553 case _counter_reset_:
555 string_vector tokens;
556 split_string(val, tokens, " ");
557 add_parsed_property(name, property_value(tokens, important));
558 break;
561 default:
562 add_parsed_property(name, property_value(val, important));
566 css_length style::parse_border_width(const string& str)
568 css_length len;
569 if (t_isdigit(str[0]) || str[0] == '.')
571 len.fromString(str);
573 else
575 int idx = value_index(str, border_width_strings);
576 if (idx >= 0)
578 len.set_value(border_width_values[idx], css_units_px);
581 return len;
584 void style::parse_two_lengths(const string& str, css_length len[2])
586 string_vector tokens;
587 split_string(str, tokens, " ");
588 if (tokens.size() == 1)
590 css_length length;
591 length.fromString(tokens[0]);
592 len[0] = len[1] = length;
594 else if (tokens.size() == 2)
596 len[0].fromString(tokens[0]);
597 len[1].fromString(tokens[1]);
601 int style::parse_four_lengths(const string& str, css_length len[4])
603 string_vector tokens;
604 split_string(str, tokens, " ");
605 if (tokens.size() == 0 || tokens.size() > 4)
607 return 0;
609 for (size_t i = 0; i < tokens.size(); i++)
611 len[i].fromString(tokens[i]);
613 return (int)tokens.size();
616 void style::parse_background(const string& val, const string& baseurl, bool important, document_container* container)
618 string_vector tokens;
619 split_string(val, tokens, ",", "", "(");
620 if (tokens.empty()) return;
622 web_color color;
623 string_vector images;
624 int_vector repeats, origins, clips, attachments;
625 length_vector x_positions, y_positions;
626 size_vector sizes;
628 for (const auto& token : tokens)
630 background bg;
631 if (!parse_one_background(token, container, bg))
632 return;
634 color = bg.m_color;
635 images.push_back(bg.m_image[0]);
636 repeats.push_back(bg.m_repeat[0]);
637 origins.push_back(bg.m_origin[0]);
638 clips.push_back(bg.m_clip[0]);
639 attachments.push_back(bg.m_attachment[0]);
640 x_positions.push_back(bg.m_position_x[0]);
641 y_positions.push_back(bg.m_position_y[0]);
642 sizes.push_back(bg.m_size[0]);
645 add_parsed_property(_background_color_, property_value(color, important));
646 add_parsed_property(_background_image_, property_value(images, important));
647 add_parsed_property(_background_image_baseurl_, property_value(baseurl, important));
648 add_parsed_property(_background_repeat_, property_value(repeats, important));
649 add_parsed_property(_background_origin_, property_value(origins, important));
650 add_parsed_property(_background_clip_, property_value(clips, important));
651 add_parsed_property(_background_attachment_, property_value(attachments, important));
652 add_parsed_property(_background_position_x_, property_value(x_positions, important));
653 add_parsed_property(_background_position_y_, property_value(y_positions, important));
654 add_parsed_property(_background_size_, property_value(sizes, important));
657 bool style::parse_one_background(const string& val, document_container* container, background& bg)
659 bg.m_color = web_color::transparent;
660 bg.m_image = {""};
661 bg.m_repeat = { background_repeat_repeat };
662 bg.m_origin = { background_box_padding };
663 bg.m_clip = { background_box_border };
664 bg.m_attachment = { background_attachment_scroll };
665 bg.m_position_x = { css_length(0, css_units_percentage) };
666 bg.m_position_y = { css_length(0, css_units_percentage) };
667 bg.m_size = { css_size(css_length::predef_value(background_size_auto), css_length::predef_value(background_size_auto)) };
669 if(val == "none")
671 return true;
674 string_vector tokens;
675 split_string(val, tokens, " \t\n\r", "", "(");
677 bool color_found = false;
678 bool image_found = false;
679 bool origin_found = false;
680 bool clip_found = false;
681 bool repeat_found = false;
682 bool attachment_found = false;
684 string position;
685 for(const auto& token : tokens)
687 int idx;
688 if(token.substr(0, 3) == "url")
690 if (image_found) return false;
691 string url;
692 css::parse_css_url(token, url);
693 bg.m_image = { url };
694 image_found = true;
695 } else if( (idx = value_index(token, background_repeat_strings)) >= 0 )
697 if (repeat_found) return false;
698 bg.m_repeat = { idx };
699 repeat_found = true;
700 } else if( (idx = value_index(token, background_attachment_strings)) >= 0 )
702 if (attachment_found) return false;
703 bg.m_attachment = { idx };
704 attachment_found = true;
705 } else if( (idx = value_index(token, background_box_strings)) >= 0 )
707 if(!origin_found)
709 bg.m_origin = { idx };
710 origin_found = true;
711 } else
713 if (clip_found) return false;
714 bg.m_clip = { idx };
715 clip_found = true;
717 } else if( value_in_list(token, background_position_strings) ||
718 token.find('/') != -1 ||
719 t_isdigit(token[0]) ||
720 token[0] == '+' ||
721 token[0] == '-' ||
722 token[0] == '.' )
724 position += " " + token;
725 } else if (web_color::is_color(token, container))
727 if (color_found) return false;
728 bg.m_color = web_color::from_string(token, container);
729 color_found = true;
731 else
733 return false;
737 if (position != "")
739 string_vector tokens;
740 split_string(position, tokens, "/");
742 if (tokens.size() > 2) return false;
744 if (tokens.size() == 2 && !parse_one_background_size(tokens[1], bg.m_size[0]))
745 return false;
747 if (tokens.size() > 0 && !parse_one_background_position(tokens[0], bg.m_position_x[0], bg.m_position_y[0]))
748 return false;
751 return true;
754 void style::parse_background_image(const string& val, const string& baseurl, bool important)
756 string_vector tokens;
757 split_string(val, tokens, ",", "", "(");
758 if (tokens.empty()) return;
760 string_vector images;
762 for (const auto& token : tokens)
764 string url;
765 css::parse_css_url(token, url);
766 images.push_back(url);
769 add_parsed_property(_background_image_, property_value(images, important));
770 add_parsed_property(_background_image_baseurl_, property_value(baseurl, important));
773 void style::parse_keyword_comma_list(string_id name, const string& val, bool important)
775 string_vector tokens;
776 split_string(val, tokens, ",");
777 if (tokens.empty()) return;
779 int_vector vec;
781 for (auto& token : tokens)
783 trim(token);
784 int idx = value_index(token, m_valid_values[name]);
785 if (idx == -1) return;
786 vec.push_back(idx);
789 add_parsed_property(name, property_value(vec, important));
792 void style::parse_background_position(const string& val, bool important)
794 string_vector tokens;
795 split_string(val, tokens, ",");
796 if (tokens.empty()) return;
798 length_vector x_positions, y_positions;
800 for (const auto& token : tokens)
802 css_length x, y;
803 if(!parse_one_background_position(token, x, y)) return;
804 x_positions.push_back(x);
805 y_positions.push_back(y);
808 add_parsed_property(_background_position_x_, property_value(x_positions, important));
809 add_parsed_property(_background_position_y_, property_value(y_positions, important));
812 bool style::parse_one_background_position(const string& val, css_length& x, css_length& y)
814 string_vector pos;
815 split_string(val, pos, " \t");
817 if (pos.empty() || pos.size() > 2)
819 return false;
822 if (pos.size() == 1)
824 if (value_in_list(pos[0], "left;right;center"))
826 x.fromString(pos[0], "left;right;center");
827 y.set_value(50, css_units_percentage);
829 else if (value_in_list(pos[0], "top;bottom;center"))
831 y.fromString(pos[0], "top;bottom;center");
832 x.set_value(50, css_units_percentage);
834 else
836 x.fromString(pos[0], "left;right;center");
837 y.set_value(50, css_units_percentage);
840 else if (pos.size() == 2)
842 if (value_in_list(pos[0], "left;right"))
844 x.fromString(pos[0], "left;right;center");
845 y.fromString(pos[1], "top;bottom;center");
847 else if (value_in_list(pos[0], "top;bottom"))
849 x.fromString(pos[1], "left;right;center");
850 y.fromString(pos[0], "top;bottom;center");
852 else if (value_in_list(pos[1], "left;right"))
854 x.fromString(pos[1], "left;right;center");
855 y.fromString(pos[0], "top;bottom;center");
857 else if (value_in_list(pos[1], "top;bottom"))
859 x.fromString(pos[0], "left;right;center");
860 y.fromString(pos[1], "top;bottom;center");
862 else
864 x.fromString(pos[0], "left;right;center");
865 y.fromString(pos[1], "top;bottom;center");
869 if (x.is_predefined())
871 switch (x.predef())
873 case 0:
874 x.set_value(0, css_units_percentage);
875 break;
876 case 1:
877 x.set_value(100, css_units_percentage);
878 break;
879 case 2:
880 x.set_value(50, css_units_percentage);
881 break;
884 if (y.is_predefined())
886 switch (y.predef())
888 case 0:
889 y.set_value(0, css_units_percentage);
890 break;
891 case 1:
892 y.set_value(100, css_units_percentage);
893 break;
894 case 2:
895 y.set_value(50, css_units_percentage);
896 break;
899 return true;
902 void style::parse_background_size(const string& val, bool important)
904 string_vector tokens;
905 split_string(val, tokens, ",");
906 if (tokens.empty()) return;
908 size_vector sizes;
910 for (const auto& token : tokens)
912 css_size size;
913 if (!parse_one_background_size(token, size)) return;
914 sizes.push_back(size);
917 add_parsed_property(_background_size_, property_value(sizes, important));
920 bool style::parse_one_background_size(const string& val, css_size& size)
922 string_vector res;
923 split_string(val, res, " \t");
924 if (res.empty())
926 return false;
929 size.width.fromString(res[0], background_size_strings);
930 if (res.size() > 1)
932 size.height.fromString(res[1], background_size_strings);
934 else
936 size.height.predef(background_size_auto);
938 return true;
941 void style::parse_font(const string& val, bool important)
943 if (val == "inherit")
945 add_parsed_property(_font_style_, property_value(important, prop_type_inherit));
946 add_parsed_property(_font_variant_, property_value(important, prop_type_inherit));
947 add_parsed_property(_font_weight_, property_value(important, prop_type_inherit));
948 add_parsed_property(_font_size_, property_value(important, prop_type_inherit));
949 add_parsed_property(_line_height_, property_value(important, prop_type_inherit));
950 return;
951 } else
953 add_parsed_property(_font_style_, property_value(font_style_normal, important));
954 add_parsed_property(_font_variant_, property_value(font_variant_normal, important));
955 add_parsed_property(_font_weight_, property_value(font_weight_normal, important));
956 add_parsed_property(_font_size_, property_value(font_size_medium, important));
957 add_parsed_property(_line_height_, property_value(line_height_normal, important));
960 string_vector tokens;
961 split_string(val, tokens, " ", "", "\"");
963 int idx;
964 bool is_family = false;
965 string font_family;
966 for(const auto& token : tokens)
968 if(is_family)
970 font_family += token;
971 continue;
974 if((idx = value_index(token, font_style_strings)) >= 0)
976 if(idx == 0)
978 add_parsed_property(_font_style_, property_value(font_style_normal, important));
979 add_parsed_property(_font_variant_, property_value(font_variant_normal, important));
980 add_parsed_property(_font_weight_, property_value(font_weight_normal, important));
981 } else
983 add_parsed_property(_font_style_, property_value(idx, important));
985 } else if((idx = value_index(token, font_weight_strings)) >= 0)
987 add_parsed_property(_font_weight_, property_value(idx, important));
988 } else if((idx = value_index(token, font_variant_strings)) >= 0)
990 add_parsed_property(_font_variant_, property_value(idx, important));
992 else if(t_isdigit(token[0]) || token[0] == '.' ||
993 value_in_list(token, font_size_strings) || token.find('/') != -1)
995 string_vector szlh;
996 split_string(token, szlh, "/");
997 if(!szlh.empty())
999 auto size = css_length::from_string(szlh[0], font_size_strings, -1);
1000 add_parsed_property(_font_size_, property_value(size, important));
1002 if (szlh.size() == 2)
1004 auto height = css_length::from_string(szlh[1], "normal", -1);
1005 add_parsed_property(_line_height_, property_value(height, important));
1008 } else
1010 is_family = true;
1011 font_family += token;
1014 add_parsed_property(_font_family_, property_value(font_family, important));
1017 void style::parse_flex(const string& val, bool important)
1019 css_length _auto = css_length::predef_value(flex_basis_auto);
1021 if (val == "initial")
1023 // 0 1 auto
1024 add_parsed_property(_flex_grow_, property_value(0.f, important));
1025 add_parsed_property(_flex_shrink_, property_value(1.f, important));
1026 add_parsed_property(_flex_basis_, property_value(_auto, important));
1028 else if (val == "auto")
1030 // 1 1 auto
1031 add_parsed_property(_flex_grow_, property_value(1.f, important));
1032 add_parsed_property(_flex_shrink_, property_value(1.f, important));
1033 add_parsed_property(_flex_basis_, property_value(_auto, important));
1035 else if (val == "none")
1037 // 0 0 auto
1038 add_parsed_property(_flex_grow_, property_value(0.f, important));
1039 add_parsed_property(_flex_shrink_, property_value(0.f, important));
1040 add_parsed_property(_flex_basis_, property_value(_auto, important));
1042 else
1044 string_vector tokens;
1045 split_string(val, tokens, " ");
1046 if (tokens.size() == 3)
1048 float grow = t_strtof(tokens[0]);
1049 float shrink = t_strtof(tokens[1]);
1050 auto basis = css_length::from_string(tokens[2], flex_basis_strings, -1);
1051 if(!basis.is_predefined() && basis.units() == css_units_none && basis.val() == 0)
1053 basis.set_value(basis.val(), css_units_px);
1056 add_parsed_property(_flex_grow_, property_value(grow, important));
1057 add_parsed_property(_flex_shrink_, property_value(shrink, important));
1058 add_parsed_property(_flex_basis_, property_value(basis, important));
1060 else if (tokens.size() == 2)
1062 float grow = t_strtof(tokens[0]);
1063 add_parsed_property(_flex_grow_, property_value(grow, important));
1065 if (litehtml::is_number(tokens[1]))
1067 float shrink = t_strtof(tokens[1]);
1068 add_parsed_property(_flex_shrink_, property_value(shrink, important));
1069 add_parsed_property(_flex_basis_, property_value(css_length(0), important));
1071 else
1073 auto basis = css_length::from_string(tokens[1], flex_basis_strings, -1);
1074 add_parsed_property(_flex_basis_, property_value(basis, important));
1077 else if (tokens.size() == 1)
1079 if (is_number(tokens[0]))
1081 float grow = t_strtof(tokens[0]);
1082 add_parsed_property(_flex_grow_, property_value(grow, important));
1083 add_parsed_property(_flex_shrink_, property_value(1.f, important));
1084 add_parsed_property(_flex_basis_, property_value(css_length(0), important));
1086 else
1088 auto basis = css_length::from_string(tokens[0], flex_basis_strings, -1);
1089 add_parsed_property(_flex_grow_, property_value(1.f, important));
1090 add_parsed_property(_flex_shrink_, property_value(1.f, important));
1091 add_parsed_property(_flex_basis_, property_value(basis, important));
1097 void style::parse_align_self(string_id name, const string& val, bool important)
1099 string_vector tokens;
1100 split_string(val, tokens, " ");
1101 if(tokens.size() == 1)
1103 int idx = value_index(val, m_valid_values[name]);
1104 if (idx >= 0)
1106 add_parsed_property(name, property_value(idx, important));
1108 } else
1110 int val1 = 0;
1111 int val2 = -1;
1112 for(auto &token : tokens)
1114 if(token == "first")
1116 val1 |= flex_align_items_first;
1117 } else if(token == "last")
1119 val1 |= flex_align_items_last;
1120 } else if(token == "safe")
1122 val1 |= flex_align_items_safe;
1123 } else if(token == "unsafe")
1125 val1 |= flex_align_items_unsafe;
1126 } else
1128 int idx = value_index(token, m_valid_values[name]);
1129 if(idx >= 0)
1131 val2 = idx;
1135 if(val2 >= 0)
1137 add_parsed_property(name, property_value(val1 | val2, important));
1142 void style::add_parsed_property( string_id name, const property_value& propval )
1144 auto prop = m_properties.find(name);
1145 if (prop != m_properties.end())
1147 if (!prop->second.m_important || (propval.m_important && prop->second.m_important))
1149 prop->second = propval;
1152 else
1154 m_properties[name] = propval;
1158 void style::remove_property( string_id name, bool important )
1160 auto prop = m_properties.find(name);
1161 if(prop != m_properties.end())
1163 if( !prop->second.m_important || (important && prop->second.m_important) )
1165 m_properties.erase(prop);
1170 void style::combine(const style& src)
1172 for (const auto& property : src.m_properties)
1174 add_parsed_property(property.first, property.second);
1178 const property_value& style::get_property(string_id name) const
1180 auto it = m_properties.find(name);
1181 if (it != m_properties.end())
1183 return it->second;
1185 static property_value dummy;
1186 return dummy;
1189 void style::subst_vars_(string& str, const element* el)
1191 while (1)
1193 auto start = str.find("var(");
1194 if (start == -1) break;
1195 if (start > 0 && isalnum(str[start - 1])) break;
1196 auto end = str.find(")", start + 4);
1197 if (end == -1) break;
1198 auto name = str.substr(start + 4, end - start - 4);
1199 trim(name);
1200 string val = el->get_custom_property(_id(name), "");
1201 str.replace(start, end - start + 1, val);
1205 void style::subst_vars(const element* el)
1207 for (auto& prop : m_properties)
1209 if (prop.second.m_type == prop_type_var)
1211 subst_vars_(prop.second.m_string, el);
1212 // re-adding the same property
1213 // if it is a custom property it will be readded as a string (currently it is prop_type_var)
1214 // if it is a standard css property it will be parsed and properly added as typed property
1215 add_property(prop.first, prop.second.m_string, "", prop.second.m_important, el->get_document()->container());
1220 } // namespace litehtml