Disable stack execution on plugins
[claws.git] / src / plugins / litehtml_viewer / litehtml / document.cpp
blobec336613d1719c6d929c54fd42e9d34cc309d9fc
1 #include "html.h"
2 #include "document.h"
3 #include "stylesheet.h"
4 #include "html_tag.h"
5 #include "el_text.h"
6 #include "el_para.h"
7 #include "el_space.h"
8 #include "el_body.h"
9 #include "el_image.h"
10 #include "el_table.h"
11 #include "el_td.h"
12 #include "el_link.h"
13 #include "el_title.h"
14 #include "el_style.h"
15 #include "el_script.h"
16 #include "el_comment.h"
17 #include "el_cdata.h"
18 #include "el_base.h"
19 #include "el_anchor.h"
20 #include "el_break.h"
21 #include "el_div.h"
22 #include "el_font.h"
23 #include "el_tr.h"
24 #include <cmath>
25 #include <cstdio>
26 #include <algorithm>
27 #include "gumbo.h"
28 #include "utf8_strings.h"
29 #include "render_item.h"
30 #include "render_table.h"
31 #include "render_block.h"
33 litehtml::document::document(document_container* objContainer)
35 m_container = objContainer;
38 litehtml::document::~document()
40 m_over_element = nullptr;
41 if(m_container)
43 for(auto& font : m_fonts)
45 m_container->delete_font(font.second.font);
50 litehtml::document::ptr litehtml::document::createFromString( const char* str, document_container* objPainter, const char* master_styles, const char* user_styles )
52 // parse document into GumboOutput
53 GumboOutput* output = gumbo_parse(str);
55 // Create litehtml::document
56 document::ptr doc = std::make_shared<document>(objPainter);
58 // Create litehtml::elements.
59 elements_list root_elements;
60 doc->create_node(output->root, root_elements, true);
61 if (!root_elements.empty())
63 doc->m_root = root_elements.back();
65 // Destroy GumboOutput
66 gumbo_destroy_output(&kGumboDefaultOptions, output);
68 if (master_styles && *master_styles)
70 doc->m_master_css.parse_stylesheet(master_styles, nullptr, doc, nullptr);
71 doc->m_master_css.sort_selectors();
73 if (user_styles && *user_styles)
75 doc->m_user_css.parse_stylesheet(user_styles, nullptr, doc, nullptr);
76 doc->m_user_css.sort_selectors();
79 // Let's process created elements tree
80 if (doc->m_root)
82 doc->container()->get_media_features(doc->m_media);
84 doc->m_root->set_pseudo_class(_root_, true);
86 // apply master CSS
87 doc->m_root->apply_stylesheet(doc->m_master_css);
89 // parse elements attributes
90 doc->m_root->parse_attributes();
92 // parse style sheets linked in document
93 media_query_list::ptr media;
94 for (const auto& css : doc->m_css)
96 if (!css.media.empty())
98 media = media_query_list::create_from_string(css.media, doc);
100 else
102 media = nullptr;
104 doc->m_styles.parse_stylesheet(css.text.c_str(), css.baseurl.c_str(), doc, media);
106 // Sort css selectors using CSS rules.
107 doc->m_styles.sort_selectors();
109 // get current media features
110 if (!doc->m_media_lists.empty())
112 doc->update_media_lists(doc->m_media);
115 // Apply parsed styles.
116 doc->m_root->apply_stylesheet(doc->m_styles);
118 // Apply user styles if any
119 doc->m_root->apply_stylesheet(doc->m_user_css);
121 // Initialize m_css
122 doc->m_root->compute_styles();
124 // Create rendering tree
125 doc->m_root_render = doc->m_root->create_render_item(nullptr);
127 // Now the m_tabular_elements is filled with tabular elements.
128 // We have to check the tabular elements for missing table elements
129 // and create the anonymous boxes in visual table layout
130 doc->fix_tables_layout();
132 // Finally initialize elements
133 // init() return pointer to the render_init element because it can change its type
134 doc->m_root_render = doc->m_root_render->init();
137 return doc;
140 litehtml::uint_ptr litehtml::document::add_font( const char* name, int size, const char* weight, const char* style, const char* decoration, font_metrics* fm )
142 uint_ptr ret = 0;
144 if(!name)
146 name = m_container->get_default_font_name();
149 char strSize[20];
150 t_itoa(size, strSize, 20, 10);
152 string key = name;
153 key += ":";
154 key += strSize;
155 key += ":";
156 key += weight;
157 key += ":";
158 key += style;
159 key += ":";
160 key += decoration;
162 if(m_fonts.find(key) == m_fonts.end())
164 font_style fs = (font_style) value_index(style, font_style_strings, font_style_normal);
165 int fw = value_index(weight, font_weight_strings, -1);
166 if(fw >= 0)
168 switch(fw)
170 case litehtml::font_weight_bold:
171 fw = 700;
172 break;
173 case litehtml::font_weight_bolder:
174 fw = 600;
175 break;
176 case litehtml::font_weight_lighter:
177 fw = 300;
178 break;
179 case litehtml::font_weight_normal:
180 fw = 400;
181 break;
182 case litehtml::font_weight_100:
183 fw = 100;
184 break;
185 case litehtml::font_weight_200:
186 fw = 200;
187 break;
188 case litehtml::font_weight_300:
189 fw = 300;
190 break;
191 case litehtml::font_weight_400:
192 fw = 400;
193 break;
194 case litehtml::font_weight_500:
195 fw = 500;
196 break;
197 case litehtml::font_weight_600:
198 fw = 600;
199 break;
200 case litehtml::font_weight_700:
201 fw = 700;
202 break;
203 case litehtml::font_weight_800:
204 fw = 800;
205 break;
206 case litehtml::font_weight_900:
207 fw = 900;
208 break;
210 } else
212 fw = atoi(weight);
213 if(fw < 100)
215 fw = 400;
219 unsigned int decor = 0;
221 if(decoration)
223 std::vector<string> tokens;
224 split_string(decoration, tokens, " ");
225 for(auto & token : tokens)
227 if(!t_strcasecmp(token.c_str(), "underline"))
229 decor |= font_decoration_underline;
230 } else if(!t_strcasecmp(token.c_str(), "line-through"))
232 decor |= font_decoration_linethrough;
233 } else if(!t_strcasecmp(token.c_str(), "overline"))
235 decor |= font_decoration_overline;
240 font_item fi= {0};
242 fi.font = m_container->create_font(name, size, fw, fs, decor, &fi.metrics);
243 m_fonts[key] = fi;
244 ret = fi.font;
245 if(fm)
247 *fm = fi.metrics;
250 return ret;
253 litehtml::uint_ptr litehtml::document::get_font( const char* name, int size, const char* weight, const char* style, const char* decoration, font_metrics* fm )
255 if(!size)
257 return 0;
259 if(!name)
261 name = m_container->get_default_font_name();
264 char strSize[20];
265 t_itoa(size, strSize, 20, 10);
267 string key = name;
268 key += ":";
269 key += strSize;
270 key += ":";
271 key += weight;
272 key += ":";
273 key += style;
274 key += ":";
275 key += decoration;
277 auto el = m_fonts.find(key);
279 if(el != m_fonts.end())
281 if(fm)
283 *fm = el->second.metrics;
285 return el->second.font;
287 return add_font(name, size, weight, style, decoration, fm);
290 int litehtml::document::render( int max_width, render_type rt )
292 int ret = 0;
293 if(m_root)
295 position client_rc;
296 m_container->get_client_rect(client_rc);
297 containing_block_context cb_context;
298 cb_context.width = max_width;
299 cb_context.width.type = containing_block_context::cbc_value_type_absolute;
300 cb_context.height = client_rc.height;
301 cb_context.height.type = containing_block_context::cbc_value_type_absolute;
303 if(rt == render_fixed_only)
305 m_fixed_boxes.clear();
306 m_root_render->render_positioned(rt);
307 } else
309 ret = m_root_render->render(0, 0, cb_context, nullptr);
310 if(m_root_render->fetch_positioned())
312 m_fixed_boxes.clear();
313 m_root_render->render_positioned(rt);
315 m_size.width = 0;
316 m_size.height = 0;
317 m_content_size.width = 0;
318 m_content_size.height = 0;
319 m_root_render->calc_document_size(m_size, m_content_size);
322 return ret;
325 void litehtml::document::draw( uint_ptr hdc, int x, int y, const position* clip )
327 if(m_root && m_root_render)
329 m_root->draw(hdc, x, y, clip, m_root_render);
330 m_root_render->draw_stacking_context(hdc, x, y, clip, true);
334 int litehtml::document::to_pixels( const char* str, int fontSize, bool* is_percent/*= 0*/ ) const
336 if(!str) return 0;
338 css_length val;
339 val.fromString(str);
340 if(is_percent && val.units() == css_units_percentage && !val.is_predefined())
342 *is_percent = true;
344 return to_pixels(val, fontSize);
347 int litehtml::document::to_pixels( const css_length& val, int fontSize, int size ) const
349 if(val.is_predefined())
351 return 0;
353 int ret;
354 switch(val.units())
356 case css_units_percentage:
357 ret = val.calc_percent(size);
358 break;
359 case css_units_em:
360 ret = round_f(val.val() * (float) fontSize);
361 break;
362 case css_units_pt:
363 ret = m_container->pt_to_px((int) val.val());
364 break;
365 case css_units_in:
366 ret = m_container->pt_to_px((int) (val.val() * 72));
367 break;
368 case css_units_cm:
369 ret = m_container->pt_to_px((int) (val.val() * 0.3937 * 72));
370 break;
371 case css_units_mm:
372 ret = m_container->pt_to_px((int) (val.val() * 0.3937 * 72) / 10);
373 break;
374 case css_units_vw:
375 ret = (int)((double)m_media.width * (double)val.val() / 100.0);
376 break;
377 case css_units_vh:
378 ret = (int)((double)m_media.height * (double)val.val() / 100.0);
379 break;
380 case css_units_vmin:
381 ret = (int)((double)std::min(m_media.height, m_media.width) * (double)val.val() / 100.0);
382 break;
383 case css_units_vmax:
384 ret = (int)((double)std::max(m_media.height, m_media.width) * (double)val.val() / 100.0);
385 break;
386 case css_units_rem:
387 ret = (int) ((double) m_root->css().get_font_size() * (double) val.val());
388 break;
389 default:
390 ret = (int) val.val();
391 break;
393 return ret;
396 void litehtml::document::cvt_units( css_length& val, int fontSize, int size ) const
398 if(val.is_predefined())
400 return;
402 int ret;
403 switch(val.units())
405 case css_units_em:
406 ret = round_f(val.val() * (float) fontSize);
407 val.set_value((float) ret, css_units_px);
408 break;
409 case css_units_pt:
410 ret = m_container->pt_to_px((int) val.val());
411 val.set_value((float) ret, css_units_px);
412 break;
413 case css_units_in:
414 ret = m_container->pt_to_px((int) (val.val() * 72));
415 val.set_value((float) ret, css_units_px);
416 break;
417 case css_units_cm:
418 ret = m_container->pt_to_px((int) (val.val() * 0.3937 * 72));
419 val.set_value((float) ret, css_units_px);
420 break;
421 case css_units_mm:
422 ret = m_container->pt_to_px((int) (val.val() * 0.3937 * 72) / 10);
423 val.set_value((float) ret, css_units_px);
424 break;
428 int litehtml::document::width() const
430 return m_size.width;
433 int litehtml::document::height() const
435 return m_size.height;
438 int litehtml::document::content_width() const
440 return m_content_size.width;
443 int litehtml::document::content_height() const
445 return m_content_size.height;
449 void litehtml::document::add_stylesheet( const char* str, const char* baseurl, const char* media )
451 if(str && str[0])
453 m_css.push_back(css_text(str, baseurl, media));
457 bool litehtml::document::on_mouse_over( int x, int y, int client_x, int client_y, position::vector& redraw_boxes )
459 if(!m_root || !m_root_render)
461 return false;
464 element::ptr over_el = m_root_render->get_element_by_point(x, y, client_x, client_y);
466 bool state_was_changed = false;
468 if(over_el != m_over_element)
470 if(m_over_element)
472 if(m_over_element->on_mouse_leave())
474 state_was_changed = true;
477 m_over_element = over_el;
480 string cursor;
482 if(m_over_element)
484 if(m_over_element->on_mouse_over())
486 state_was_changed = true;
488 cursor = m_over_element->css().get_cursor();
491 m_container->set_cursor(cursor.c_str());
493 if(state_was_changed)
495 return m_root->find_styles_changes(redraw_boxes);
497 return false;
500 bool litehtml::document::on_mouse_leave( position::vector& redraw_boxes )
502 if(!m_root || !m_root_render)
504 return false;
506 if(m_over_element)
508 if(m_over_element->on_mouse_leave())
510 return m_root->find_styles_changes(redraw_boxes);
513 return false;
516 bool litehtml::document::on_lbutton_down( int x, int y, int client_x, int client_y, position::vector& redraw_boxes )
518 if(!m_root || !m_root_render)
520 return false;
523 element::ptr over_el = m_root_render->get_element_by_point(x, y, client_x, client_y);
525 bool state_was_changed = false;
527 if(over_el != m_over_element)
529 if(m_over_element)
531 if(m_over_element->on_mouse_leave())
533 state_was_changed = true;
536 m_over_element = over_el;
537 if(m_over_element)
539 if(m_over_element->on_mouse_over())
541 state_was_changed = true;
546 string cursor;
548 if(m_over_element)
550 if(m_over_element->on_lbutton_down())
552 state_was_changed = true;
554 cursor = m_over_element->css().get_cursor();
557 m_container->set_cursor(cursor.c_str());
559 if(state_was_changed)
561 return m_root->find_styles_changes(redraw_boxes);
564 return false;
567 bool litehtml::document::on_lbutton_up( int x, int y, int client_x, int client_y, position::vector& redraw_boxes )
569 if(!m_root || !m_root_render)
571 return false;
573 if(m_over_element)
575 if(m_over_element->on_lbutton_up())
577 return m_root->find_styles_changes(redraw_boxes);
580 return false;
583 litehtml::element::ptr litehtml::document::create_element(const char* tag_name, const string_map& attributes)
585 element::ptr newTag;
586 document::ptr this_doc = shared_from_this();
587 if(m_container)
589 newTag = m_container->create_element(tag_name, attributes, this_doc);
591 if(!newTag)
593 if(!strcmp(tag_name, "br"))
595 newTag = std::make_shared<litehtml::el_break>(this_doc);
596 } else if(!strcmp(tag_name, "p"))
598 newTag = std::make_shared<litehtml::el_para>(this_doc);
599 } else if(!strcmp(tag_name, "img"))
601 newTag = std::make_shared<litehtml::el_image>(this_doc);
602 } else if(!strcmp(tag_name, "table"))
604 newTag = std::make_shared<litehtml::el_table>(this_doc);
605 } else if(!strcmp(tag_name, "td") || !strcmp(tag_name, "th"))
607 newTag = std::make_shared<litehtml::el_td>(this_doc);
608 } else if(!strcmp(tag_name, "link"))
610 newTag = std::make_shared<litehtml::el_link>(this_doc);
611 } else if(!strcmp(tag_name, "title"))
613 newTag = std::make_shared<litehtml::el_title>(this_doc);
614 } else if(!strcmp(tag_name, "a"))
616 newTag = std::make_shared<litehtml::el_anchor>(this_doc);
617 } else if(!strcmp(tag_name, "tr"))
619 newTag = std::make_shared<litehtml::el_tr>(this_doc);
620 } else if(!strcmp(tag_name, "style"))
622 newTag = std::make_shared<litehtml::el_style>(this_doc);
623 } else if(!strcmp(tag_name, "base"))
625 newTag = std::make_shared<litehtml::el_base>(this_doc);
626 } else if(!strcmp(tag_name, "body"))
628 newTag = std::make_shared<litehtml::el_body>(this_doc);
629 } else if(!strcmp(tag_name, "div"))
631 newTag = std::make_shared<litehtml::el_div>(this_doc);
632 } else if(!strcmp(tag_name, "script"))
634 newTag = std::make_shared<litehtml::el_script>(this_doc);
635 } else if(!strcmp(tag_name, "font"))
637 newTag = std::make_shared<litehtml::el_font>(this_doc);
638 } else
640 newTag = std::make_shared<litehtml::html_tag>(this_doc);
644 if(newTag)
646 newTag->set_tagName(tag_name);
647 for (const auto & attribute : attributes)
649 newTag->set_attr(attribute.first.c_str(), attribute.second.c_str());
653 return newTag;
656 void litehtml::document::get_fixed_boxes( position::vector& fixed_boxes )
658 fixed_boxes = m_fixed_boxes;
661 void litehtml::document::add_fixed_box( const position& pos )
663 m_fixed_boxes.push_back(pos);
666 bool litehtml::document::media_changed()
668 container()->get_media_features(m_media);
669 if (update_media_lists(m_media))
671 m_root->refresh_styles();
672 m_root->compute_styles();
673 return true;
675 return false;
678 bool litehtml::document::lang_changed()
680 if(!m_media_lists.empty())
682 string culture;
683 container()->get_language(m_lang, culture);
684 if(!culture.empty())
686 m_culture = m_lang + '-' + culture;
688 else
690 m_culture.clear();
692 m_root->refresh_styles();
693 m_root->compute_styles();
694 return true;
696 return false;
699 bool litehtml::document::update_media_lists(const media_features& features)
701 bool update_styles = false;
702 for(auto & m_media_list : m_media_lists)
704 if(m_media_list->apply_media_features(features))
706 update_styles = true;
709 return update_styles;
712 void litehtml::document::add_media_list( const media_query_list::ptr& list )
714 if(list)
716 if(std::find(m_media_lists.begin(), m_media_lists.end(), list) == m_media_lists.end())
718 m_media_lists.push_back(list);
723 void litehtml::document::create_node(void* gnode, elements_list& elements, bool parseTextNode)
725 auto* node = (GumboNode*)gnode;
726 switch (node->type)
728 case GUMBO_NODE_ELEMENT:
730 string_map attrs;
731 GumboAttribute* attr;
732 for (unsigned int i = 0; i < node->v.element.attributes.length; i++)
734 attr = (GumboAttribute*)node->v.element.attributes.data[i];
735 attrs[attr->name] = attr->value;
739 element::ptr ret;
740 const char* tag = gumbo_normalized_tagname(node->v.element.tag);
741 if (tag[0])
743 ret = create_element(tag, attrs);
745 else
747 if (node->v.element.original_tag.data && node->v.element.original_tag.length)
749 std::string strA;
750 gumbo_tag_from_original_text(&node->v.element.original_tag);
751 strA.append(node->v.element.original_tag.data, node->v.element.original_tag.length);
752 ret = create_element(strA.c_str(), attrs);
755 if (!strcmp(tag, "script"))
757 parseTextNode = false;
759 if (ret)
761 elements_list child;
762 for (unsigned int i = 0; i < node->v.element.children.length; i++)
764 child.clear();
765 create_node(static_cast<GumboNode*> (node->v.element.children.data[i]), child, parseTextNode);
766 std::for_each(child.begin(), child.end(),
767 [&ret](element::ptr& el)
769 ret->appendChild(el);
773 elements.push_back(ret);
776 break;
777 case GUMBO_NODE_TEXT:
779 if (!parseTextNode)
781 elements.push_back(std::make_shared<el_text>(node->v.text.text, shared_from_this()));
783 else
785 m_container->split_text(node->v.text.text,
786 [this, &elements](const char* text) { elements.push_back(std::make_shared<el_text>(text, shared_from_this())); },
787 [this, &elements](const char* text) { elements.push_back(std::make_shared<el_space>(text, shared_from_this())); });
790 break;
791 case GUMBO_NODE_CDATA:
793 element::ptr ret = std::make_shared<el_cdata>(shared_from_this());
794 ret->set_data(node->v.text.text);
795 elements.push_back(ret);
797 break;
798 case GUMBO_NODE_COMMENT:
800 element::ptr ret = std::make_shared<el_comment>(shared_from_this());
801 ret->set_data(node->v.text.text);
802 elements.push_back(ret);
804 break;
805 case GUMBO_NODE_WHITESPACE:
807 string str = node->v.text.text;
808 for (size_t i = 0; i < str.length(); i++)
810 elements.push_back(std::make_shared<el_space>(str.substr(i, 1).c_str(), shared_from_this()));
813 break;
814 default:
815 break;
819 void litehtml::document::fix_tables_layout()
821 for (const auto& el_ptr : m_tabular_elements)
823 switch (el_ptr->src_el()->css().get_display())
825 case display_inline_table:
826 case display_table:
827 fix_table_children(el_ptr, display_table_row_group, "table-row-group");
828 break;
829 case display_table_footer_group:
830 case display_table_row_group:
831 case display_table_header_group:
833 auto parent = el_ptr->parent();
834 if (parent)
836 if (parent->src_el()->css().get_display() != display_inline_table)
837 fix_table_parent(el_ptr, display_table, "table");
839 fix_table_children(el_ptr, display_table_row, "table-row");
841 break;
842 case display_table_row:
843 fix_table_parent(el_ptr, display_table_row_group, "table-row-group");
844 fix_table_children(el_ptr, display_table_cell, "table-cell");
845 break;
846 case display_table_cell:
847 fix_table_parent(el_ptr, display_table_row, "table-row");
848 break;
849 // TODO: make table layout fix for table-caption, table-column etc. elements
850 case display_table_caption:
851 case display_table_column:
852 case display_table_column_group:
853 default:
854 break;
859 void litehtml::document::fix_table_children(const std::shared_ptr<render_item>& el_ptr, style_display disp, const char* disp_str)
861 std::list<std::shared_ptr<render_item>> tmp;
862 auto first_iter = el_ptr->children().begin();
863 auto cur_iter = el_ptr->children().begin();
865 auto flush_elements = [&]()
867 element::ptr annon_tag = std::make_shared<html_tag>(el_ptr->src_el(), string("display:") + disp_str);
868 std::shared_ptr<render_item> annon_ri;
869 if(annon_tag->css().get_display() == display_table_cell)
871 annon_tag->set_tagName("table_cell");
872 annon_ri = std::make_shared<render_item_block>(annon_tag);
873 } else if(annon_tag->css().get_display() == display_table_row)
875 annon_ri = std::make_shared<render_item_table_row>(annon_tag);
876 } else
878 annon_ri = std::make_shared<render_item_table_part>(annon_tag);
880 for(const auto& el : tmp)
882 annon_ri->add_child(el);
884 // add annon item as tabular for future processing
885 add_tabular(annon_ri);
886 annon_ri->parent(el_ptr);
887 first_iter = el_ptr->children().insert(first_iter, annon_ri);
888 cur_iter = std::next(first_iter);
889 while (cur_iter != el_ptr->children().end() && (*cur_iter)->parent() != el_ptr)
891 cur_iter = el_ptr->children().erase(cur_iter);
893 first_iter = cur_iter;
894 tmp.clear();
897 while (cur_iter != el_ptr->children().end())
899 if ((*cur_iter)->src_el()->css().get_display() != disp)
901 if (!(*cur_iter)->src_el()->is_table_skip() || ((*cur_iter)->src_el()->is_table_skip() && !tmp.empty()))
903 if (disp != display_table_row_group || (*cur_iter)->src_el()->css().get_display() != display_table_caption)
905 if (tmp.empty())
907 first_iter = cur_iter;
909 tmp.push_back((*cur_iter));
912 cur_iter++;
914 else if (!tmp.empty())
916 flush_elements();
918 else
920 cur_iter++;
923 if (!tmp.empty())
925 flush_elements();
929 void litehtml::document::fix_table_parent(const std::shared_ptr<render_item>& el_ptr, style_display disp, const char* disp_str)
931 auto parent = el_ptr->parent();
933 if (parent->src_el()->css().get_display() != disp)
935 auto this_element = std::find_if(parent->children().begin(), parent->children().end(),
936 [&](const std::shared_ptr<render_item>& el)
938 if (el == el_ptr)
940 return true;
942 return false;
945 if (this_element != parent->children().end())
947 style_display el_disp = el_ptr->src_el()->css().get_display();
948 auto first = this_element;
949 auto last = this_element;
950 auto cur = this_element;
952 // find first element with same display
953 while (true)
955 if (cur == parent->children().begin()) break;
956 cur--;
957 if ((*cur)->src_el()->is_table_skip() || (*cur)->src_el()->css().get_display() == el_disp)
959 first = cur;
961 else
963 break;
967 // find last element with same display
968 cur = this_element;
969 while (true)
971 cur++;
972 if (cur == parent->children().end()) break;
974 if ((*cur)->src_el()->is_table_skip() || (*cur)->src_el()->css().get_display() == el_disp)
976 last = cur;
978 else
980 break;
984 // extract elements with the same display and wrap them with anonymous object
985 element::ptr annon_tag = std::make_shared<html_tag>(parent->src_el(), string("display:") + disp_str);
986 std::shared_ptr<render_item> annon_ri;
987 if(annon_tag->css().get_display() == display_table || annon_tag->css().get_display() == display_inline_table)
989 annon_ri = std::make_shared<render_item_table>(annon_tag);
990 } else if(annon_tag->css().get_display() == display_table_row)
992 annon_ri = std::make_shared<render_item_table_row>(annon_tag);
993 } else
995 annon_ri = std::make_shared<render_item_table_part>(annon_tag);
997 std::for_each(first, std::next(last, 1),
998 [&annon_ri](std::shared_ptr<render_item>& el)
1000 annon_ri->add_child(el);
1003 first = parent->children().erase(first, std::next(last));
1004 parent->children().insert(first, annon_ri);
1005 add_tabular(annon_ri);
1006 annon_ri->parent(parent);
1011 void litehtml::document::append_children_from_string(element& parent, const char* str)
1013 // parent must belong to this document
1014 if (parent.get_document().get() != this)
1016 return;
1019 // parse document into GumboOutput
1020 GumboOutput* output = gumbo_parse(str);
1022 // Create litehtml::elements.
1023 elements_list child_elements;
1024 create_node(output->root, child_elements, true);
1026 // Destroy GumboOutput
1027 gumbo_destroy_output(&kGumboDefaultOptions, output);
1029 // Let's process created elements tree
1030 for (const auto& child : child_elements)
1032 // Add the child element to parent
1033 parent.appendChild(child);
1035 // apply master CSS
1036 child->apply_stylesheet(m_master_css);
1038 // parse elements attributes
1039 child->parse_attributes();
1041 // Apply parsed styles.
1042 child->apply_stylesheet(m_styles);
1044 // Apply user styles if any
1045 child->apply_stylesheet(m_user_css);
1047 // Initialize m_css
1048 child->compute_styles();
1050 // Now the m_tabular_elements is filled with tabular elements.
1051 // We have to check the tabular elements for missing table elements
1052 // and create the anonymous boxes in visual table layout
1053 fix_tables_layout();
1055 // Finally initialize elements
1056 //child->init();
1060 void litehtml::document::dump(dumper& cout)
1062 if(m_root_render)
1064 m_root_render->dump(cout);