From 705c4d24c9c61edffc82864bf9c24384dc29a8d7 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Mon, 18 Mar 2024 12:13:54 +0300 Subject: litehtml - lightweight html renderer --- libs/litehtml/containers/cairo/cairo_borders.cpp | 342 +++++++++++++++++++++++ 1 file changed, 342 insertions(+) create mode 100644 libs/litehtml/containers/cairo/cairo_borders.cpp (limited to 'libs/litehtml/containers/cairo/cairo_borders.cpp') diff --git a/libs/litehtml/containers/cairo/cairo_borders.cpp b/libs/litehtml/containers/cairo/cairo_borders.cpp new file mode 100644 index 0000000000..21ae6db4cd --- /dev/null +++ b/libs/litehtml/containers/cairo/cairo_borders.cpp @@ -0,0 +1,342 @@ +#include +#include "cairo_borders.h" +#include + +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif + +void cairo::add_path_arc(cairo_t* cr, double x, double y, double rx, double ry, double a1, double a2, bool neg) +{ + if(rx > 0 && ry > 0) + { + cairo_save(cr); + + cairo_translate(cr, x, y); + cairo_scale(cr, 1, ry / rx); + cairo_translate(cr, -x, -y); + + if(neg) + { + cairo_arc_negative(cr, x, y, rx, a1, a2); + } else + { + cairo_arc(cr, x, y, rx, a1, a2); + } + + cairo_restore(cr); + } else + { + cairo_move_to(cr, x, y); + } +} + +/** + * Draw border at the left side. Use the only function to draw all border by using rotation transfer + * @param cr cairo context + * @param left left position of the border + * @param top top position of the border + * @param bottom bottom position of the border + * @param data border data + */ +void cairo::border::draw_border() +{ + cairo_save(cr); + + if(radius_top_x && radius_top_y) + { + double start_angle = M_PI; + double end_angle = start_angle + M_PI / 2.0 / ((double) top_border_width / (double) border_width + 1); + + add_path_arc(cr, + left + radius_top_x, + top + radius_top_y, + radius_top_x - border_width, + radius_top_y - border_width + (border_width - top_border_width), + start_angle, + end_angle, false); + + add_path_arc(cr, + left + radius_top_x, + top + radius_top_y, + radius_top_x, + radius_top_y, + end_angle, + start_angle, true); + } else + { + cairo_move_to(cr, left + border_width, top + top_border_width); + cairo_line_to(cr, left, top); + } + + if(radius_bottom_x && radius_bottom_y) + { + cairo_line_to(cr, left, bottom - radius_bottom_y); + + double end_angle = M_PI; + double start_angle = end_angle - M_PI / 2.0 / ((double) bottom_border_width / (double) border_width + 1); + + add_path_arc(cr, + left + radius_bottom_x, + bottom - radius_bottom_y, + radius_bottom_x, + radius_bottom_y, + end_angle, + start_angle, true); + + add_path_arc(cr, + left + radius_bottom_x, + bottom - radius_bottom_y, + radius_bottom_x - border_width, + radius_bottom_y - border_width + (border_width - bottom_border_width), + start_angle, + end_angle, false); + } else + { + cairo_line_to(cr, left, bottom); + cairo_line_to(cr, left + border_width, bottom - bottom_border_width); + } + cairo_clip(cr); + + switch (style) + { + case litehtml::border_style_dotted: + draw_dotted(); + break; + case litehtml::border_style_dashed: + draw_dashed(); + break; + case litehtml::border_style_double: + draw_double(); + break; + case litehtml::border_style_inset: + draw_inset_outset(true); + break; + case litehtml::border_style_outset: + draw_inset_outset(false); + break; + case litehtml::border_style_groove: + draw_groove_ridge(true); + break; + case litehtml::border_style_ridge: + draw_groove_ridge(false); + break; + default: + draw_solid(); + break; + } + + cairo_restore(cr); +} + +void cairo::border::draw_line(double line_offset, double top_line_offset, double bottom_line_offset) +{ + if(radius_top_x && radius_top_y) + { + double end_angle = M_PI; + double start_angle = end_angle + M_PI / 2.0 / ((double) top_border_width / (double) border_width + 1); + + add_path_arc(cr, + left + radius_top_x, + top + radius_top_y, + radius_top_x - line_offset, + radius_top_y - line_offset + (line_offset - top_line_offset), + start_angle, + end_angle, true); + } else + { + cairo_move_to(cr, left + line_offset, top); + } + + if(radius_bottom_x && radius_bottom_y) + { + cairo_line_to(cr, left + line_offset, bottom - radius_bottom_y); + + double start_angle = M_PI; + double end_angle = start_angle - M_PI / 2.0 / ((double) bottom_border_width / (double) border_width + 1); + + add_path_arc(cr, + left + radius_bottom_x, + bottom - radius_bottom_y, + radius_bottom_x - line_offset, + radius_bottom_y - line_offset + (line_offset - bottom_line_offset), + start_angle, + end_angle, true); + } else + { + cairo_line_to(cr, left + line_offset, bottom); + } +} + +void cairo::border::draw_inset_outset(bool is_inset) +{ + litehtml::web_color line_color; + litehtml::web_color light_color = color; + litehtml::web_color dark_color = color.darken(0.33); + if(color.red == 0 && color.green == 0 && color.blue == 0) + { + dark_color.red = dark_color.green = dark_color.blue = 0x4C; + light_color.red = light_color.green = light_color.blue = 0xB2; + } + + if (real_side == left_side || real_side == top_side) + { + line_color = is_inset ? dark_color : light_color; + } else + { + line_color = is_inset ? light_color : dark_color; + } + draw_line(border_width / 2.0, + top_border_width / 2.0, + bottom_border_width / 2.0); + cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); + cairo_set_dash(cr, nullptr, 0, 0); + set_color(cr, line_color); + cairo_set_line_width(cr, border_width); + cairo_stroke(cr); +} + +void cairo::border::draw_double() +{ + if (border_width < 3) + { + draw_solid(); + } else + { + cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); + cairo_set_dash(cr, nullptr, 0, 0); + set_color(cr, color); + + double line_width = border_width / 3.0; + cairo_set_line_width(cr, line_width); + // draw external line + draw_line(line_width / 2.0, + top_border_width / 6.0, + bottom_border_width / 6.0); + cairo_stroke(cr); + // draw internal line + draw_line(border_width - line_width / 2.0, + top_border_width - top_border_width / 6.0, + bottom_border_width - bottom_border_width / 6.0); + cairo_stroke(cr); + } +} + +void cairo::border::draw_dashed() +{ + draw_line(border_width / 2.0, + top_border_width / 2.0, + bottom_border_width / 2.0); + + int line_length = std::abs(bottom - top); + int segment_length = border_width * 3; + int seg_nums = line_length / segment_length; + if(seg_nums < 2) + { + seg_nums = 2; + } if(seg_nums % 2 != 0) + { + seg_nums = seg_nums + 1; + } + seg_nums++; + double seg_len = (double) line_length / (double) seg_nums; + + double dashes[2]; + dashes[0] = seg_len; + dashes[1] = seg_len; + cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); + cairo_set_dash(cr, dashes, 2, 0); + set_color(cr, color); + cairo_set_line_width(cr, border_width); + cairo_stroke(cr); +} + +void cairo::border::draw_solid() +{ + draw_line(border_width / 2.0, + top_border_width / 2.0, + bottom_border_width / 2.0); + cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); + cairo_set_dash(cr, nullptr, 0, 0); + set_color(cr, color); + cairo_set_line_width(cr, border_width); + cairo_stroke(cr); +} + +void cairo::border::draw_dotted() +{ + draw_line(border_width / 2.0, + top_border_width / 2.0, + bottom_border_width / 2.0); + + double line_length = std::abs(bottom - top); + + double dot_size = border_width; + int num_dots = (int) std::nearbyint(line_length / (dot_size * 2.0)); + if(num_dots < 2) + { + num_dots = 2; + } if(num_dots % 2 != 0) + { + num_dots = num_dots + 1; + } + num_dots++; + double space_len = ((double) line_length - (double) border_width) / (num_dots - 1.0); + + double dashes[2]; + dashes[0] = 0; + dashes[1] = space_len; + cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); + cairo_set_dash(cr, dashes, 2, -dot_size / 2.0); + + set_color(cr, color); + cairo_set_line_width(cr, border_width); + cairo_stroke(cr); +} + +void cairo::border::draw_groove_ridge(bool is_groove) +{ + if(border_width == 1) + { + draw_solid(); + } else + { + litehtml::web_color inner_line_color; + litehtml::web_color outer_line_color; + litehtml::web_color light_color = color; + litehtml::web_color dark_color = color.darken(0.33); + if (color.red == 0 && color.green == 0 && color.blue == 0) + { + dark_color.red = dark_color.green = dark_color.blue = 0x4C; + light_color.red = light_color.green = light_color.blue = 0xB2; + } + + if (real_side == left_side || real_side == top_side) + { + outer_line_color = is_groove ? dark_color : light_color; + inner_line_color = is_groove ? light_color : dark_color; + } else + { + outer_line_color = is_groove ? light_color : dark_color; + inner_line_color = is_groove ? dark_color : light_color; + } + + cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); + cairo_set_dash(cr, nullptr, 0, 0); + + double line_width = border_width / 2.0; + cairo_set_line_width(cr, line_width); + // draw external line + draw_line(line_width / 2.0, + top_border_width / 4.0, + bottom_border_width / 4.0); + set_color(cr, outer_line_color); + cairo_stroke(cr); + // draw internal line + set_color(cr, inner_line_color); + draw_line(border_width - line_width / 2.0, + top_border_width - top_border_width / 4.0, + bottom_border_width - bottom_border_width / 4.0); + cairo_stroke(cr); + } +} -- cgit v1.2.3