#include "draw_buffer.h"
#include "litehtml/types.h"
void litebrowser::draw_buffer::on_scroll(const draw_page_function_t& cb_draw, int left, int top, const litehtml::position::vector& fixed_boxes)
{
if(m_width <= 0 || m_height <= 0 || !m_draw_buffer)
return;
top = fix_position(top);
left = fix_position(left);
if(m_left != left || m_top != top)
{
litehtml::position rec_current(m_left, m_top, m_width, m_height); litehtml::position rec_new(left, top, m_width, m_height); litehtml::position rec_clean = rec_current.intersect(rec_new); if(rec_clean.empty() || rec_new == rec_current)
{
m_left = left;
m_top = top;
redraw(cb_draw);
} else
{
int shift_x = m_left - left;
int shift_y = m_top - top;
int surface_shift_x = (int) std::floor((double) shift_x * m_scale_factor);
int surface_shift_y = (int) std::floor((double) shift_y * m_scale_factor);
auto new_surface = make_surface(m_width, m_height, m_scale_factor);
cairo_t* cr = cairo_create(new_surface);
cairo_rectangle(cr, (rec_clean.x - left) * m_scale_factor - m_scale_factor,
(rec_clean.y - top) * m_scale_factor - m_scale_factor,
std::ceil((double) rec_clean.width * m_scale_factor) + 2.0 * m_scale_factor,
std::ceil((double) rec_clean.height * m_scale_factor) + 2.0 * m_scale_factor);
cairo_clip(cr);
cairo_set_source_surface(cr, m_draw_buffer, surface_shift_x, surface_shift_y);
cairo_paint(cr);
cairo_destroy(cr);
cairo_surface_destroy(m_draw_buffer);
m_draw_buffer = new_surface;
m_left = left;
m_top = top;
int right = fix_position(m_left + m_width);
int bottom = fix_position(m_top + m_height);
int clean_right = fix_position(rec_clean.x + rec_clean.width);
int clean_bottom = fix_position(rec_clean.y + rec_clean.height);
if(rec_clean.x > m_left)
{
redraw_area(cb_draw, m_left, rec_clean.y, rec_clean.x - m_left, rec_clean.height);
}
if(clean_right < right)
{
redraw_area(cb_draw, clean_right, rec_clean.y, right - clean_right, rec_clean.height);
}
if(rec_clean.y > m_top)
{
redraw_area(cb_draw, m_left, m_top, m_width, rec_clean.y - m_top);
}
if(clean_bottom < bottom)
{
redraw_area(cb_draw, m_left, clean_bottom, m_width, bottom - clean_bottom);
}
for(const auto& box : fixed_boxes)
{
redraw_area(cb_draw, m_left + box.left(), m_top + box.top(), box.width, box.height);
redraw_area(cb_draw, m_left + box.left() + shift_x, m_top + box.top() + shift_y, box.width, box.height);
}
}
}
}
void litebrowser::draw_buffer::redraw_area(const draw_page_function_t& cb_draw, int x, int y, int width, int height)
{
if(m_draw_buffer)
{
int fixed_left = fix_position(x - m_left);
int fixed_right = fix_position(x - m_left + width);
int fixed_top = fix_position(y - m_top);
int fixed_bottom = fix_position(y - m_top + height);
if(fixed_right < x + width)
fixed_right += m_min_int_position;
if(fixed_bottom < y + height)
fixed_bottom += m_min_int_position;
int fixed_x = fixed_left;
int fixed_y = fixed_top;
int fixed_width = fixed_right - fixed_left;
int fixed_height = fixed_bottom - fixed_top;
int s_x = (int) std::round((double) fixed_x * m_scale_factor);
int s_y = (int) std::round((double) fixed_y * m_scale_factor);
int s_width = (int) std::round((double) fixed_width * m_scale_factor);
int s_height = (int) std::round((double) fixed_height * m_scale_factor);
litehtml::position pos{(litehtml::pixel_t) fixed_x, (litehtml::pixel_t) fixed_y, (litehtml::pixel_t) fixed_width, (litehtml::pixel_t) fixed_height};
cairo_t* cr = cairo_create(m_draw_buffer);
cairo_rectangle(cr, s_x, s_y, s_width, s_height);
cairo_clip(cr);
cairo_rectangle(cr, s_x, s_y, s_width, s_height);
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
cairo_fill(cr);
cairo_scale(cr, m_scale_factor, m_scale_factor);
cb_draw(cr, -m_left, -m_top, &pos);
cairo_destroy(cr);
}
}