#ifndef LH_RENDER_ITEM_H #define LH_RENDER_ITEM_H #include #include #include #include #include "types.h" #include "line_box.h" #include "table.h" #include "formatting_context.h" namespace litehtml { class element; class render_item : public std::enable_shared_from_this { protected: std::shared_ptr m_element; std::weak_ptr m_parent; std::list> m_children; margins m_margins; margins m_padding; margins m_borders; position m_pos; bool m_skip; std::vector> m_positioned; containing_block_context calculate_containing_block_context(const containing_block_context& cb_context); void calc_cb_length(const css_length& len, int percent_base, containing_block_context::typed_int& out_value) const; virtual int _render(int x, int y, const containing_block_context& containing_block_size, formatting_context* fmt_ctx, bool second_pass = false) { return 0; } public: explicit render_item(std::shared_ptr src_el); virtual ~render_item() = default; std::list>& children() { return m_children; } position& pos() { return m_pos; } bool skip() const { return m_skip; } void skip(bool val) { m_skip = val; } int right() const { return left() + width(); } int left() const { return m_pos.left() - m_margins.left - m_padding.left - m_borders.left; } int top() const { return m_pos.top() - m_margins.top - m_padding.top - m_borders.top; } int bottom() const { return top() + height(); } int height() const { return m_pos.height + m_margins.height() + m_padding.height() + m_borders.height(); } int width() const { return m_pos.width + m_margins.width() + m_padding.width() + m_borders.width(); } int padding_top() const { return m_padding.top; } int padding_bottom() const { return m_padding.bottom; } int padding_left() const { return m_padding.left; } int padding_right() const { return m_padding.right; } int border_top() const { return m_borders.top; } int border_bottom() const { return m_borders.bottom; } int border_left() const { return m_borders.left; } int border_right() const { return m_borders.right; } int margin_top() const { return m_margins.top; } int margin_bottom() const { return m_margins.bottom; } int margin_left() const { return m_margins.left; } int margin_right() const { return m_margins.right; } std::shared_ptr parent() const { return m_parent.lock(); } margins& get_margins() { return m_margins; } margins& get_paddings() { return m_padding; } void set_paddings(const margins& val) { m_padding = val; } margins& get_borders() { return m_borders; } /** * Top offset to the element content. Includes paddings, margins and borders. */ int content_offset_top() const { return m_margins.top + m_padding.top + m_borders.top; } /** * Bottom offset to the element content. Includes paddings, margins and borders. */ inline int content_offset_bottom() const { return m_margins.bottom + m_padding.bottom + m_borders.bottom; } /** * Left offset to the element content. Includes paddings, margins and borders. */ int content_offset_left() const { return m_margins.left + m_padding.left + m_borders.left; } /** * Right offset to the element content. Includes paddings, margins and borders. */ int content_offset_right() const { return m_margins.right + m_padding.right + m_borders.right; } /** * Sum of left and right offsets to the element content. Includes paddings, margins and borders. */ int content_offset_width() const { return content_offset_left() + content_offset_right(); } /** * Sum of top and bottom offsets to the element content. Includes paddings, margins and borders. */ int content_offset_height() const { return content_offset_top() + content_offset_bottom(); } int box_sizing_left() const { if(css().get_box_sizing() == box_sizing_border_box) { return m_padding.left + m_borders.left; } return 0; } int box_sizing_right() const { if(css().get_box_sizing() == box_sizing_border_box) { return m_padding.right + m_borders.right; } return 0; } int box_sizing_width() const { return box_sizing_left() + box_sizing_right(); } int box_sizing_top() const { if(css().get_box_sizing() == box_sizing_border_box) { return m_padding.top + m_borders.top; } return 0; } int box_sizing_bottom() const { if(css().get_box_sizing() == box_sizing_border_box) { return m_padding.bottom + m_borders.bottom; } return 0; } int box_sizing_height() const { return box_sizing_top() + box_sizing_bottom(); } void parent(const std::shared_ptr& par) { m_parent = par; } const std::shared_ptr& src_el() const { return m_element; } const css_properties& css() const { return m_element->css(); } void add_child(const std::shared_ptr& ri) { m_children.push_back(ri); ri->parent(shared_from_this()); } bool is_root() const { return m_parent.expired(); } bool collapse_top_margin() const { return !m_borders.top && !m_padding.top && m_element->in_normal_flow() && m_element->css().get_float() == float_none && m_margins.top >= 0 && !is_flex_item() && !is_root(); } bool collapse_bottom_margin() const { return !m_borders.bottom && !m_padding.bottom && m_element->in_normal_flow() && m_element->css().get_float() == float_none && m_margins.bottom >= 0 && !is_root(); } bool is_visible() const { return !(m_skip || src_el()->css().get_display() == display_none || src_el()->css().get_visibility() != visibility_visible); } bool is_flex_item() const { auto par = parent(); if(par && (par->css().get_display() == display_inline_flex || par->css().get_display() == display_flex)) { return true; } return false; } int render(int x, int y, const containing_block_context& containing_block_size, formatting_context* fmt_ctx, bool second_pass = false); void apply_relative_shift(const containing_block_context &containing_block_size); void calc_outlines( int parent_width ); int calc_auto_margins(int parent_width); // returns left margin virtual std::shared_ptr init(); virtual void apply_vertical_align() {} /** * Get first baseline position. Default position is element bottom without bottom margin. * @returns offset of the first baseline from element top */ virtual int get_first_baseline() { return height() - margin_bottom(); } /** * Get last baseline position. Default position is element bottom without bottom margin. * @returns offset of the last baseline from element top */ virtual int get_last_baseline() { return height() - margin_bottom(); } virtual std::shared_ptr clone() { return std::make_shared(src_el()); } std::tuple< std::shared_ptr, std::shared_ptr, std::shared_ptr > split_inlines(); bool fetch_positioned(); void render_positioned(render_type rt = render_all); void add_positioned(const std::shared_ptr &el); void get_redraw_box(litehtml::position& pos, int x = 0, int y = 0); void calc_document_size( litehtml::size& sz, litehtml::size& content_size, int x = 0, int y = 0 ); virtual void get_inline_boxes( position::vector& boxes ) const {}; virtual void set_inline_boxes( position::vector& boxes ) {}; virtual void add_inline_box( const position& box ) {}; virtual void clear_inline_boxes() {}; void draw_stacking_context( uint_ptr hdc, int x, int y, const position* clip, bool with_positioned ); virtual void draw_children( uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex ); virtual int get_draw_vertical_offset() { return 0; } virtual std::shared_ptr get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex); std::shared_ptr get_element_by_point(int x, int y, int client_x, int client_y); bool is_point_inside( int x, int y ); void dump(litehtml::dumper& cout); position get_placement() const; /** * Returns the boxes of rendering element. All coordinates are absolute * * @param redraw_boxes [out] resulting rendering boxes * @return */ void get_rendering_boxes( position::vector& redraw_boxes); }; } #endif //LH_RENDER_ITEM_H