Cogs.Core
element.cpp
1#ifdef _WIN32
2#pragma warning(disable: 4100) // unreferenced formal parameter
3#elif defined(__clang__)
4#pragma clang diagnostic ignored "-Wunused-parameter"
5#endif
6
7#include "html.h"
8#include "element.h"
9#include "document.h"
10#include "gumbo.h"
11
12#define LITEHTML_EMPTY_FUNC {}
13#define LITEHTML_RETURN_FUNC(ret) {return ret;}
14
15litehtml::element::element(const std::shared_ptr<litehtml::document>& doc) : m_doc(doc)
16{
17 m_box = 0;
18 m_skip = false;
19 m_userdata = nullptr;
20 m_userdatageneration = 0;
21}
22
23litehtml::element::~element()
24{
25}
26
27bool litehtml::element::is_point_inside( int x, int y )
28{
29 if(get_display() != display_inline && get_display() != display_table_row)
30 {
31 position pos = m_pos;
32 pos += m_padding;
33 pos += m_borders;
34 if(pos.is_point_inside(x, y))
35 {
36 return true;
37 } else
38 {
39 return false;
40 }
41 } else
42 {
43 position::vector boxes;
44 get_inline_boxes(boxes);
45 for(position::vector::iterator box = boxes.begin(); box != boxes.end(); box++)
46 {
47 if(box->is_point_inside(x, y))
48 {
49 return true;
50 }
51 }
52 }
53 return false;
54}
55
56litehtml::web_color litehtml::element::get_color( const tchar_t* prop_name, bool inherited, const litehtml::web_color& def_color )
57{
58 const tchar_t* clrstr = get_style_property(prop_name, inherited, 0);
59 if(!clrstr)
60 {
61 return def_color;
62 }
63 return web_color::from_string(clrstr, get_document()->container());
64}
65
66litehtml::position litehtml::element::get_placement() const
67{
68 litehtml::position pos = m_pos;
69 element::ptr cur_el = parent();
70 while(cur_el)
71 {
72 pos.x += cur_el->m_pos.x;
73 pos.y += cur_el->m_pos.y;
74 cur_el = cur_el->parent();
75 }
76 return pos;
77}
78
79bool litehtml::element::is_inline_box() const
80{
81 style_display d = get_display();
82 if( d == display_inline ||
83 d == display_inline_table ||
84 d == display_inline_block ||
85 d == display_inline_text)
86 {
87 return true;
88 }
89 return false;
90}
91
92bool litehtml::element::collapse_top_margin() const
93{
94 if(!m_borders.top && !m_padding.top && in_normal_flow() && get_float() == float_none && m_margins.top >= 0 && have_parent())
95 {
96 return true;
97 }
98 return false;
99}
100
101bool litehtml::element::collapse_bottom_margin() const
102{
103 if(!m_borders.bottom && !m_padding.bottom && in_normal_flow() && get_float() == float_none && m_margins.bottom >= 0 && have_parent())
104 {
105 return true;
106 }
107 return false;
108}
109
110bool litehtml::element::get_predefined_height(int& p_height) const
111{
112 css_length h = get_css_height();
113 if(h.is_predefined())
114 {
115 p_height = m_pos.height;
116 return false;
117 }
118 if(h.units() == css_units_percentage)
119 {
120 element::ptr el_parent = parent();
121 if (!el_parent)
122 {
123 position client_pos;
124 get_document()->container()->get_client_rect(client_pos);
125 p_height = h.calc_percent(client_pos.height);
126 return true;
127 } else
128 {
129 int ph = 0;
130 if (el_parent->get_predefined_height(ph))
131 {
132 p_height = h.calc_percent(ph);
133 if (is_body())
134 {
135 p_height -= content_margins_height();
136 }
137 return true;
138 } else
139 {
140 p_height = m_pos.height;
141 return false;
142 }
143 }
144 }
145 p_height = get_document()->cvt_units(h, get_font_size());
146 return true;
147}
148
149void litehtml::element::calc_document_size( litehtml::size& sz, int x /*= 0*/, int y /*= 0*/ )
150{
151 if(is_visible())
152 {
153 sz.width = std::max(sz.width, x + right());
154 sz.height = std::max(sz.height, y + bottom());
155 }
156}
157
158void litehtml::element::get_redraw_box(litehtml::position& pos, int x /*= 0*/, int y /*= 0*/)
159{
160 if(is_visible())
161 {
162 int p_left = std::min(pos.left(), x + m_pos.left() - m_padding.left - m_borders.left);
163 int p_right = std::max(pos.right(), x + m_pos.right() + m_padding.left + m_borders.left);
164 int p_top = std::min(pos.top(), y + m_pos.top() - m_padding.top - m_borders.top);
165 int p_bottom = std::max(pos.bottom(), y + m_pos.bottom() + m_padding.bottom + m_borders.bottom);
166
167 pos.x = p_left;
168 pos.y = p_top;
169 pos.width = p_right - p_left;
170 pos.height = p_bottom - p_top;
171 }
172}
173
174int litehtml::element::calc_width(int defVal) const
175{
176 css_length w = get_css_width();
177 if(w.is_predefined())
178 {
179 return defVal;
180 }
181 if(w.units() == css_units_percentage)
182 {
183 element::ptr el_parent = parent();
184 if (!el_parent)
185 {
186 position client_pos;
187 get_document()->container()->get_client_rect(client_pos);
188 return w.calc_percent(client_pos.width);
189 } else
190 {
191 int pw = el_parent->calc_width(defVal);
192 if (is_body())
193 {
194 pw -= content_margins_width();
195 }
196 return w.calc_percent(pw);
197 }
198 }
199 return get_document()->cvt_units(w, get_font_size());
200}
201
202bool litehtml::element::is_ancestor(const ptr &el) const
203{
204 element::ptr el_parent = parent();
205 while(el_parent && el_parent != el)
206 {
207 el_parent = el_parent->parent();
208 }
209 if(el_parent)
210 {
211 return true;
212 }
213 return false;
214}
215
216int litehtml::element::get_inline_shift_left()
217{
218 int ret = 0;
219 element::ptr el_parent = parent();
220 if (el_parent)
221 {
222 if (el_parent->get_display() == display_inline)
223 {
224 style_display disp = get_display();
225
226 if (disp == display_inline_text || disp == display_inline_block)
227 {
228 element::ptr el = shared_from_this();
229 while (el_parent && el_parent->get_display() == display_inline)
230 {
231 if (el_parent->is_first_child_inline(el))
232 {
233 ret += el_parent->padding_left() + el_parent->border_left() + el_parent->margin_left();
234 }
235 el = el_parent;
236 el_parent = el_parent->parent();
237 }
238 }
239 }
240 }
241
242 return ret;
243}
244
245int litehtml::element::get_inline_shift_right()
246{
247 int ret = 0;
248 element::ptr el_parent = parent();
249 if (el_parent)
250 {
251 if (el_parent->get_display() == display_inline)
252 {
253 style_display disp = get_display();
254
255 if (disp == display_inline_text || disp == display_inline_block)
256 {
257 element::ptr el = shared_from_this();
258 while (el_parent && el_parent->get_display() == display_inline)
259 {
260 if (el_parent->is_last_child_inline(el))
261 {
262 ret += el_parent->padding_right() + el_parent->border_right() + el_parent->margin_right();
263 }
264 el = el_parent;
265 el_parent = el_parent->parent();
266 }
267 }
268 }
269 }
270
271 return ret;
272}
273
274void litehtml::element::apply_relative_shift(int parent_width)
275{
276 css_offsets offsets;
277 if (get_element_position(&offsets) == element_position_relative)
278 {
279 element::ptr parent_ptr = parent();
280 if (!offsets.left.is_predefined())
281 {
282 m_pos.x += offsets.left.calc_percent(parent_width);
283 }
284 else if (!offsets.right.is_predefined())
285 {
286 m_pos.x -= offsets.right.calc_percent(parent_width);
287 }
288 if (!offsets.top.is_predefined())
289 {
290 int h = 0;
291
292 if (offsets.top.units() == css_units_percentage)
293 {
294 element::ptr el_parent = parent();
295 if (el_parent)
296 {
297 el_parent->get_predefined_height(h);
298 }
299 }
300
301 m_pos.y += offsets.top.calc_percent(h);
302 }
303 else if (!offsets.bottom.is_predefined())
304 {
305 int h = 0;
306
307 if (offsets.top.units() == css_units_percentage)
308 {
309 element::ptr el_parent = parent();
310 if (el_parent)
311 {
312 el_parent->get_predefined_height(h);
313 }
314 }
315
316 m_pos.y -= offsets.bottom.calc_percent(h);
317 }
318 }
319}
320
321void litehtml::element::set_inner_html(const litehtml::tchar_t* str, litehtml::css* user_styles)
322{
323 // parse document into GumboOutput
325
326 options.fragment_context = gumbo_tag_enum(get_tagName());
327
328 GumboOutput* output = gumbo_parse_with_options(&options, str, strlen(str));
329
330 m_children.clear();
331
332 if( output->root->v.element.children.length )
333 {
334 document::ptr doc = m_doc.lock();
335
336 document::create_node(output->root->v.element.children.data[0], m_children, true, doc);
338
339 for (auto& child : m_children)
340 {
341 child->parent(shared_from_this());
342 }
343
344 if( doc->is_initialised() )
345 {
346 for (auto& child : m_children)
347 {
348 // Let's process created elements tree
349 // apply master CSS
350 child->apply_stylesheet(doc->get_context()->master_css());
351
352 // parse elements attributes
353 child->parse_attributes();
354
355 // Apply parsed styles.
356 child->apply_stylesheet(doc->get_styles());
357
358 // Apply user styles if any
359 if (user_styles)
360 {
361 child->apply_stylesheet(*user_styles);
362 }
363
364 // Parse applied styles in the elements
365 child->parse_styles();
366
367 // Finally initialize elements
368 child->init();
369 }
370 }
371 }
372}
373
374void litehtml::element::calc_auto_margins(int parent_width) LITEHTML_EMPTY_FUNC
375const litehtml::background* litehtml::element::get_background(bool own_only) LITEHTML_RETURN_FUNC(0)
376litehtml::element::ptr litehtml::element::get_element_by_point(int x, int y, int client_x, int client_y) LITEHTML_RETURN_FUNC(0)
377litehtml::element::ptr litehtml::element::get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex) LITEHTML_RETURN_FUNC(0)
378void litehtml::element::get_line_left_right( int y, int def_right, int& ln_left, int& ln_right ) LITEHTML_EMPTY_FUNC
379void litehtml::element::add_style( const litehtml::style& st ) LITEHTML_EMPTY_FUNC
380void litehtml::element::select_all(const css_selector& selector, litehtml::elements_vector& res) LITEHTML_EMPTY_FUNC
381litehtml::elements_vector litehtml::element::select_all(const litehtml::css_selector& selector) LITEHTML_RETURN_FUNC(litehtml::elements_vector())
382litehtml::elements_vector litehtml::element::select_all(const litehtml::tstring& selector) LITEHTML_RETURN_FUNC(litehtml::elements_vector())
383litehtml::element::ptr litehtml::element::select_one( const css_selector& selector ) LITEHTML_RETURN_FUNC(0)
384litehtml::element::ptr litehtml::element::select_one( const tstring& selector ) LITEHTML_RETURN_FUNC(0)
385litehtml::element::ptr litehtml::element::find_adjacent_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/) LITEHTML_RETURN_FUNC(0)
386litehtml::element::ptr litehtml::element::find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/) LITEHTML_RETURN_FUNC(0)
387bool litehtml::element::is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const LITEHTML_RETURN_FUNC(false)
388bool litehtml::element::is_nth_child(const element::ptr&, int num, int off, bool of_type) const LITEHTML_RETURN_FUNC(false)
389bool litehtml::element::is_only_child(const element::ptr& el, bool of_type) const LITEHTML_RETURN_FUNC(false)
390litehtml::overflow litehtml::element::get_overflow() const LITEHTML_RETURN_FUNC(overflow_visible)
391void litehtml::element::draw_children( uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex ) LITEHTML_EMPTY_FUNC
392void litehtml::element::draw_stacking_context( uint_ptr hdc, int x, int y, const position* clip, bool with_positioned ) LITEHTML_EMPTY_FUNC
393void litehtml::element::render_positioned(render_type rt) LITEHTML_EMPTY_FUNC
394int litehtml::element::get_zindex() const LITEHTML_RETURN_FUNC(0)
395bool litehtml::element::fetch_positioned() LITEHTML_RETURN_FUNC(false)
396litehtml::visibility litehtml::element::get_visibility() const LITEHTML_RETURN_FUNC(visibility_visible)
397void litehtml::element::apply_vertical_align() LITEHTML_EMPTY_FUNC
398void litehtml::element::set_css_width( css_length& w ) LITEHTML_EMPTY_FUNC
399litehtml::element::ptr litehtml::element::get_child( size_t idx ) const LITEHTML_RETURN_FUNC(0)
400size_t litehtml::element::get_children_count() const LITEHTML_RETURN_FUNC(0)
401void litehtml::element::calc_outlines( int parent_width ) LITEHTML_EMPTY_FUNC
402litehtml::css_length litehtml::element::get_css_width() const LITEHTML_RETURN_FUNC(css_length())
403litehtml::css_length litehtml::element::get_css_height() const LITEHTML_RETURN_FUNC(css_length())
404litehtml::element_clear litehtml::element::get_clear() const LITEHTML_RETURN_FUNC(clear_none)
405litehtml::css_length litehtml::element::get_css_left() const LITEHTML_RETURN_FUNC(css_length())
406litehtml::css_length litehtml::element::get_css_right() const LITEHTML_RETURN_FUNC(css_length())
407litehtml::css_length litehtml::element::get_css_top() const LITEHTML_RETURN_FUNC(css_length())
408litehtml::css_length litehtml::element::get_css_bottom() const LITEHTML_RETURN_FUNC(css_length())
409litehtml::css_offsets litehtml::element::get_css_offsets() const LITEHTML_RETURN_FUNC(css_offsets())
410litehtml::vertical_align litehtml::element::get_vertical_align() const LITEHTML_RETURN_FUNC(va_baseline)
411int litehtml::element::place_element(const ptr &el, int max_width) LITEHTML_RETURN_FUNC(0)
412int litehtml::element::render_inline(const ptr &container, int max_width) LITEHTML_RETURN_FUNC(0)
413void litehtml::element::add_positioned(const ptr &el) LITEHTML_EMPTY_FUNC
414int litehtml::element::find_next_line_top( int top, int width, int def_right ) LITEHTML_RETURN_FUNC(0)
415litehtml::element_float litehtml::element::get_float() const LITEHTML_RETURN_FUNC(float_none)
416void litehtml::element::add_float(const ptr &el, int x, int y) LITEHTML_EMPTY_FUNC
417void litehtml::element::update_floats(int dy, const ptr &parent) LITEHTML_EMPTY_FUNC
418int litehtml::element::get_line_left( int y ) LITEHTML_RETURN_FUNC(0)
419int litehtml::element::get_line_right( int y, int def_right ) LITEHTML_RETURN_FUNC(def_right)
420int litehtml::element::get_left_floats_height() const LITEHTML_RETURN_FUNC(0)
421int litehtml::element::get_right_floats_height() const LITEHTML_RETURN_FUNC(0)
422int litehtml::element::get_floats_height(element_float el_float) const LITEHTML_RETURN_FUNC(0)
423bool litehtml::element::is_floats_holder() const LITEHTML_RETURN_FUNC(false)
424void litehtml::element::get_content_size( size& sz, int max_width ) LITEHTML_EMPTY_FUNC
425void litehtml::element::init() LITEHTML_EMPTY_FUNC
426int litehtml::element::render( int x, int y, int max_width, bool second_pass ) LITEHTML_RETURN_FUNC(0)
427bool litehtml::element::appendChild(const ptr &el) LITEHTML_RETURN_FUNC(false)
428bool litehtml::element::removeChild(const ptr &el) LITEHTML_RETURN_FUNC(false)
429void litehtml::element::clearRecursive() LITEHTML_EMPTY_FUNC
430const litehtml::tchar_t* litehtml::element::get_tagName() const LITEHTML_RETURN_FUNC(_t(""))
431void litehtml::element::set_tagName( const tchar_t* tag ) LITEHTML_EMPTY_FUNC
432void litehtml::element::set_data( const tchar_t* data ) LITEHTML_EMPTY_FUNC
433void litehtml::element::set_attr( const tchar_t* name, const tchar_t* val ) LITEHTML_EMPTY_FUNC
434void litehtml::element::apply_stylesheet( const litehtml::css& stylesheet ) LITEHTML_EMPTY_FUNC
435void litehtml::element::refresh_styles() LITEHTML_EMPTY_FUNC
436void litehtml::element::on_click() LITEHTML_EMPTY_FUNC
437void litehtml::element::init_font() LITEHTML_EMPTY_FUNC
438void litehtml::element::get_inline_boxes( position::vector& boxes ) LITEHTML_EMPTY_FUNC
439void litehtml::element::parse_styles( bool is_reparse /*= false*/ ) LITEHTML_EMPTY_FUNC
440const litehtml::tchar_t* litehtml::element::get_attr( const tchar_t* name, const tchar_t* def /*= 0*/ ) const LITEHTML_RETURN_FUNC(def)
441bool litehtml::element::is_white_space() const LITEHTML_RETURN_FUNC(false)
442bool litehtml::element::is_body() const LITEHTML_RETURN_FUNC(false)
443bool litehtml::element::is_break() const LITEHTML_RETURN_FUNC(false)
444int litehtml::element::get_base_line() LITEHTML_RETURN_FUNC(0)
445bool litehtml::element::on_mouse_over() LITEHTML_RETURN_FUNC(false)
446bool litehtml::element::on_mouse_leave() LITEHTML_RETURN_FUNC(false)
447bool litehtml::element::on_lbutton_down() LITEHTML_RETURN_FUNC(false)
448bool litehtml::element::on_lbutton_up() LITEHTML_RETURN_FUNC(false)
449bool litehtml::element::find_styles_changes( position::vector& redraw_boxes, int x, int y ) LITEHTML_RETURN_FUNC(false)
450const litehtml::tchar_t* litehtml::element::get_cursor() LITEHTML_RETURN_FUNC(0)
451litehtml::white_space litehtml::element::get_white_space() const LITEHTML_RETURN_FUNC(white_space_normal)
452litehtml::style_display litehtml::element::get_display() const LITEHTML_RETURN_FUNC(display_none)
453bool litehtml::element::set_pseudo_class( const tchar_t* pclass, bool add ) LITEHTML_RETURN_FUNC(false)
454bool litehtml::element::set_class( const tchar_t* pclass, bool add ) LITEHTML_RETURN_FUNC(false)
455litehtml::element_position litehtml::element::get_element_position(css_offsets* offsets) const LITEHTML_RETURN_FUNC(element_position_static)
456bool litehtml::element::is_replaced() const LITEHTML_RETURN_FUNC(false)
457int litehtml::element::line_height() const LITEHTML_RETURN_FUNC(0)
458void litehtml::element::draw( uint_ptr hdc, int x, int y, const position* clip ) LITEHTML_EMPTY_FUNC
459void litehtml::element::draw_background( uint_ptr hdc, int x, int y, const position* clip ) LITEHTML_EMPTY_FUNC
460const litehtml::tchar_t* litehtml::element::get_style_property( const tchar_t* name, bool inherited, const tchar_t* def /*= 0*/ ) LITEHTML_RETURN_FUNC(0)
461litehtml::uint_ptr litehtml::element::get_font( font_metrics* fm /*= 0*/ ) LITEHTML_RETURN_FUNC(0)
462int litehtml::element::get_font_size() const LITEHTML_RETURN_FUNC(0)
463void litehtml::element::get_text( tstring& text ) LITEHTML_EMPTY_FUNC
464void litehtml::element::parse_attributes() LITEHTML_EMPTY_FUNC
465int litehtml::element::select( const css_selector& selector, bool apply_pseudo) LITEHTML_RETURN_FUNC(select_no_match)
466int litehtml::element::select( const css_element_selector& selector, bool apply_pseudo /*= true*/ ) LITEHTML_RETURN_FUNC(select_no_match)
467litehtml::element::ptr litehtml::element::find_ancestor(const css_selector& selector, bool apply_pseudo, bool* is_pseudo) LITEHTML_RETURN_FUNC(0)
468bool litehtml::element::is_first_child_inline(const element::ptr& el) const LITEHTML_RETURN_FUNC(false)
469bool litehtml::element::is_last_child_inline(const element::ptr& el) LITEHTML_RETURN_FUNC(false)
470bool litehtml::element::have_inline_child() const LITEHTML_RETURN_FUNC(false)
void gumbo_destroy_output(const GumboOptions *options, GumboOutput *output)
GumboTag gumbo_tag_enum(const char *tagname)
GumboOutput * gumbo_parse_with_options(const GumboOptions *options, const char *buffer, size_t buffer_length)
const GumboOptions kGumboDefaultOptions