summaryrefslogtreecommitdiff
path: root/libs/litehtml/containers/cairo/container_cairo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/litehtml/containers/cairo/container_cairo.cpp')
-rw-r--r--libs/litehtml/containers/cairo/container_cairo.cpp539
1 files changed, 539 insertions, 0 deletions
diff --git a/libs/litehtml/containers/cairo/container_cairo.cpp b/libs/litehtml/containers/cairo/container_cairo.cpp
new file mode 100644
index 0000000000..1c66c48279
--- /dev/null
+++ b/libs/litehtml/containers/cairo/container_cairo.cpp
@@ -0,0 +1,539 @@
+#include "container_cairo.h"
+#include "cairo_borders.h"
+#include <cmath>
+
+#ifndef M_PI
+# define M_PI 3.14159265358979323846
+#endif
+
+
+int container_cairo::pt_to_px(int pt ) const
+{
+ double dpi = get_screen_dpi();
+
+ return (int) ((double) pt * dpi / 72.0);
+}
+
+int container_cairo::get_default_font_size() const
+{
+ return pt_to_px(12);
+}
+
+void container_cairo::draw_list_marker(litehtml::uint_ptr hdc, const litehtml::list_marker& marker )
+{
+ if(!marker.image.empty())
+ {
+ /*litehtml::string url;
+ make_url(marker.image.c_str(), marker.baseurl, url);
+
+ lock_images_cache();
+ images_map::iterator img_i = m_images.find(url.c_str());
+ if(img_i != m_images.end())
+ {
+ if(img_i->second)
+ {
+ draw_txdib((cairo_t*) hdc, img_i->second, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height);
+ }
+ }
+ unlock_images_cache();*/
+ } else
+ {
+ switch(marker.marker_type)
+ {
+ case litehtml::list_style_type_circle:
+ {
+ draw_ellipse((cairo_t*) hdc, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height, marker.color, 1);
+ }
+ break;
+ case litehtml::list_style_type_disc:
+ {
+ fill_ellipse((cairo_t*) hdc, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height, marker.color);
+ }
+ break;
+ case litehtml::list_style_type_square:
+ if(hdc)
+ {
+ auto* cr = (cairo_t*) hdc;
+ cairo_save(cr);
+
+ cairo_new_path(cr);
+ cairo_rectangle(cr, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height);
+
+ set_color(cr, marker.color);
+ cairo_fill(cr);
+ cairo_restore(cr);
+ }
+ break;
+ default:
+ /*do nothing*/
+ break;
+ }
+ }
+}
+
+void container_cairo::get_image_size(const char* src, const char* baseurl, litehtml::size& sz )
+{
+ litehtml::string url;
+ make_url(src, baseurl, url);
+
+ auto img = get_image(url);
+ if(img)
+ {
+ sz.width = cairo_image_surface_get_width(img);
+ sz.height = cairo_image_surface_get_height(img);
+ cairo_surface_destroy(img);
+ } else
+ {
+ sz.width = 0;
+ sz.height = 0;
+ }
+}
+
+void container_cairo::draw_background(litehtml::uint_ptr hdc, const std::vector<litehtml::background_paint>& bgvec )
+{
+ auto* cr = (cairo_t*) hdc;
+ cairo_save(cr);
+ apply_clip(cr);
+
+ const auto& bg = bgvec.back();
+
+ rounded_rectangle(cr, bg.border_box, bg.border_radius);
+ cairo_clip(cr);
+
+ cairo_rectangle(cr, bg.clip_box.x, bg.clip_box.y, bg.clip_box.width, bg.clip_box.height);
+ cairo_clip(cr);
+
+ if(bg.color.alpha)
+ {
+ set_color(cr, bg.color);
+ cairo_paint(cr);
+ }
+
+ for (int i = (int)bgvec.size() - 1; i >= 0; i--)
+ {
+ const auto& bg = bgvec[i];
+
+ if(bg.image_size.height == 0 || bg.image_size.width == 0) continue;
+
+ cairo_rectangle(cr, bg.clip_box.x, bg.clip_box.y, bg.clip_box.width, bg.clip_box.height);
+ cairo_clip(cr);
+
+ std::string url;
+ make_url(bg.image.c_str(), bg.baseurl.c_str(), url);
+
+ auto bgbmp = get_image(url);
+ if(bgbmp)
+ {
+ if(bg.image_size.width != cairo_image_surface_get_width(bgbmp) || bg.image_size.height != cairo_image_surface_get_height(bgbmp))
+ {
+ auto new_img = scale_surface(bgbmp, bg.image_size.width, bg.image_size.height);
+ cairo_surface_destroy(bgbmp);
+ bgbmp = new_img;
+ }
+
+ cairo_pattern_t *pattern = cairo_pattern_create_for_surface(bgbmp);
+ cairo_matrix_t flib_m;
+ cairo_matrix_init_identity(&flib_m);
+ cairo_matrix_translate(&flib_m, -bg.position_x, -bg.position_y);
+ cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
+ cairo_pattern_set_matrix (pattern, &flib_m);
+
+ switch(bg.repeat)
+ {
+ case litehtml::background_repeat_no_repeat:
+ draw_pixbuf(cr, bgbmp, bg.position_x, bg.position_y, cairo_image_surface_get_width(bgbmp), cairo_image_surface_get_height(bgbmp));
+ break;
+
+ case litehtml::background_repeat_repeat_x:
+ cairo_set_source(cr, pattern);
+ cairo_rectangle(cr, bg.clip_box.left(), bg.position_y, bg.clip_box.width, cairo_image_surface_get_height(bgbmp));
+ cairo_fill(cr);
+ break;
+
+ case litehtml::background_repeat_repeat_y:
+ cairo_set_source(cr, pattern);
+ cairo_rectangle(cr, bg.position_x, bg.clip_box.top(), cairo_image_surface_get_width(bgbmp), bg.clip_box.height);
+ cairo_fill(cr);
+ break;
+
+ case litehtml::background_repeat_repeat:
+ cairo_set_source(cr, pattern);
+ cairo_rectangle(cr, bg.clip_box.left(), bg.clip_box.top(), bg.clip_box.width, bg.clip_box.height);
+ cairo_fill(cr);
+ break;
+ }
+
+ cairo_pattern_destroy(pattern);
+ cairo_surface_destroy(bgbmp);
+ }
+ }
+
+ cairo_restore(cr);
+}
+
+void container_cairo::make_url(const char* url, const char* /*basepath*/, litehtml::string& out)
+{
+ out = url;
+}
+
+void container_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);
+ }
+}
+
+void container_cairo::draw_borders(litehtml::uint_ptr hdc, const litehtml::borders& borders, const litehtml::position& draw_pos, bool /*root*/)
+{
+ auto* cr = (cairo_t*) hdc;
+ cairo_save(cr);
+ apply_clip(cr);
+
+ cairo_new_path(cr);
+
+ int bdr_top = 0;
+ int bdr_bottom = 0;
+ int bdr_left = 0;
+ int bdr_right = 0;
+
+ if(borders.top.width != 0 && borders.top.style > litehtml::border_style_hidden)
+ {
+ bdr_top = (int) borders.top.width;
+ }
+ if(borders.bottom.width != 0 && borders.bottom.style > litehtml::border_style_hidden)
+ {
+ bdr_bottom = (int) borders.bottom.width;
+ }
+ if(borders.left.width != 0 && borders.left.style > litehtml::border_style_hidden)
+ {
+ bdr_left = (int) borders.left.width;
+ }
+ if(borders.right.width != 0 && borders.right.style > litehtml::border_style_hidden)
+ {
+ bdr_right = (int) borders.right.width;
+ }
+
+ // draw right border
+ if(bdr_right)
+ {
+ cairo_matrix_t save_matrix;
+ cairo_get_matrix(cr, &save_matrix);
+ cairo_translate(cr, draw_pos.left(), draw_pos.top());
+ cairo_rotate(cr, M_PI);
+ cairo_translate(cr, -draw_pos.left(), -draw_pos.top());
+
+ cairo::border border(cr, draw_pos.left() - draw_pos.width, draw_pos.top() - draw_pos.height, draw_pos.top());
+ border.real_side = cairo::border::right_side;
+ border.color = borders.right.color;
+ border.style = borders.right.style;
+ border.border_width = bdr_right;
+ border.top_border_width = bdr_bottom;
+ border.bottom_border_width = bdr_top;
+ border.radius_top_x = borders.radius.bottom_right_x;
+ border.radius_top_y = borders.radius.bottom_right_y;
+ border.radius_bottom_x = borders.radius.top_right_x;
+ border.radius_bottom_y = borders.radius.top_right_y;
+ border.draw_border();
+
+ cairo_set_matrix(cr, &save_matrix);
+ }
+
+ // draw bottom border
+ if(bdr_bottom)
+ {
+ cairo_matrix_t save_matrix;
+ cairo_get_matrix(cr, &save_matrix);
+ cairo_translate(cr, draw_pos.left(), draw_pos.top());
+ cairo_rotate(cr, - M_PI / 2.0);
+ cairo_translate(cr, -draw_pos.left(), -draw_pos.top());
+
+ cairo::border border(cr, draw_pos.left() - draw_pos.height, draw_pos.top(), draw_pos.top() + draw_pos.width);
+ border.real_side = cairo::border::bottom_side;
+ border.color = borders.bottom.color;
+ border.style = borders.bottom.style;
+ border.border_width = bdr_bottom;
+ border.top_border_width = bdr_left;
+ border.bottom_border_width = bdr_right;
+ border.radius_top_x = borders.radius.bottom_left_x;
+ border.radius_top_y = borders.radius.bottom_left_y;
+ border.radius_bottom_x = borders.radius.bottom_right_x;
+ border.radius_bottom_y = borders.radius.bottom_right_y;
+ border.draw_border();
+
+ cairo_set_matrix(cr, &save_matrix);
+ }
+
+ // draw top border
+ if(bdr_top)
+ {
+ cairo_matrix_t save_matrix;
+ cairo_get_matrix(cr, &save_matrix);
+ cairo_translate(cr, draw_pos.left(), draw_pos.top());
+ cairo_rotate(cr, M_PI / 2.0);
+ cairo_translate(cr, -draw_pos.left(), -draw_pos.top());
+
+ cairo::border border(cr, draw_pos.left(), draw_pos.top() - draw_pos.width, draw_pos.top());
+ border.real_side = cairo::border::top_side;
+ border.color = borders.top.color;
+ border.style = borders.top.style;
+ border.border_width = bdr_top;
+ border.top_border_width = bdr_right;
+ border.bottom_border_width = bdr_left;
+ border.radius_top_x = borders.radius.top_right_x;
+ border.radius_top_y = borders.radius.top_right_y;
+ border.radius_bottom_x = borders.radius.top_left_x;
+ border.radius_bottom_y = borders.radius.top_left_y;
+ border.draw_border();
+
+ cairo_set_matrix(cr, &save_matrix);
+ }
+
+ // draw left border
+ if(bdr_left)
+ {
+ cairo::border border(cr, draw_pos.left(), draw_pos.top(), draw_pos.bottom());
+ border.real_side = cairo::border::left_side;
+ border.color = borders.left.color;
+ border.style = borders.left.style;
+ border.border_width = bdr_left;
+ border.top_border_width = bdr_top;
+ border.bottom_border_width = bdr_bottom;
+ border.radius_top_x = borders.radius.top_left_x;
+ border.radius_top_y = borders.radius.top_left_y;
+ border.radius_bottom_x = borders.radius.bottom_left_x;
+ border.radius_bottom_y = borders.radius.bottom_left_y;
+ border.draw_border();
+ }
+ cairo_restore(cr);
+}
+
+void container_cairo::transform_text(litehtml::string& /*text*/, litehtml::text_transform /*tt*/)
+{
+
+}
+
+void container_cairo::set_clip(const litehtml::position& pos, const litehtml::border_radiuses& bdr_radius )
+{
+ m_clips.emplace_back(pos, bdr_radius);
+}
+
+void container_cairo::del_clip()
+{
+ if(!m_clips.empty())
+ {
+ m_clips.pop_back();
+ }
+}
+
+void container_cairo::apply_clip(cairo_t* cr )
+{
+ for(const auto& clip_box : m_clips)
+ {
+ rounded_rectangle(cr, clip_box.box, clip_box.radius);
+ cairo_clip(cr);
+ }
+}
+
+void container_cairo::draw_ellipse(cairo_t* cr, int x, int y, int width, int height, const litehtml::web_color& color, int line_width )
+{
+ if(!cr || !width || !height) return;
+ cairo_save(cr);
+
+ apply_clip(cr);
+
+ cairo_new_path(cr);
+
+ cairo_translate (cr, x + width / 2.0, y + height / 2.0);
+ cairo_scale (cr, width / 2.0, height / 2.0);
+ cairo_arc (cr, 0, 0, 1, 0, 2 * M_PI);
+
+ set_color(cr, color);
+ cairo_set_line_width(cr, line_width);
+ cairo_stroke(cr);
+
+ cairo_restore(cr);
+}
+
+void container_cairo::fill_ellipse(cairo_t* cr, int x, int y, int width, int height, const litehtml::web_color& color )
+{
+ if(!cr || !width || !height) return;
+ cairo_save(cr);
+
+ apply_clip(cr);
+
+ cairo_new_path(cr);
+
+ cairo_translate (cr, x + width / 2.0, y + height / 2.0);
+ cairo_scale (cr, width / 2.0, height / 2.0);
+ cairo_arc (cr, 0, 0, 1, 0, 2 * M_PI);
+
+ set_color(cr, color);
+ cairo_fill(cr);
+
+ cairo_restore(cr);
+}
+
+void container_cairo::clear_images()
+{
+/* for(images_map::iterator i = m_images.begin(); i != m_images.end(); i++)
+ {
+ if(i->second)
+ {
+ delete i->second;
+ }
+ }
+ m_images.clear();
+*/
+}
+
+const char* container_cairo::get_default_font_name() const
+{
+ return "Times New Roman";
+}
+
+std::shared_ptr<litehtml::element> container_cairo::create_element(const char */*tag_name*/,
+ const litehtml::string_map &/*attributes*/,
+ const std::shared_ptr<litehtml::document> &/*doc*/)
+{
+ return nullptr;
+}
+
+void container_cairo::rounded_rectangle(cairo_t* cr, const litehtml::position &pos, const litehtml::border_radiuses &radius )
+{
+ cairo_new_path(cr);
+ if(radius.top_left_x && radius.top_left_y)
+ {
+ add_path_arc(cr,
+ pos.left() + radius.top_left_x,
+ pos.top() + radius.top_left_y,
+ radius.top_left_x,
+ radius.top_left_y,
+ M_PI,
+ M_PI * 3.0 / 2.0, false);
+ } else
+ {
+ cairo_move_to(cr, pos.left(), pos.top());
+ }
+
+ cairo_line_to(cr, pos.right() - radius.top_right_x, pos.top());
+
+ if(radius.top_right_x && radius.top_right_y)
+ {
+ add_path_arc(cr,
+ pos.right() - radius.top_right_x,
+ pos.top() + radius.top_right_y,
+ radius.top_right_x,
+ radius.top_right_y,
+ M_PI * 3.0 / 2.0,
+ 2.0 * M_PI, false);
+ }
+
+ cairo_line_to(cr, pos.right(), pos.bottom() - radius.bottom_right_x);
+
+ if(radius.bottom_right_x && radius.bottom_right_y)
+ {
+ add_path_arc(cr,
+ pos.right() - radius.bottom_right_x,
+ pos.bottom() - radius.bottom_right_y,
+ radius.bottom_right_x,
+ radius.bottom_right_y,
+ 0,
+ M_PI / 2.0, false);
+ }
+
+ cairo_line_to(cr, pos.left() - radius.bottom_left_x, pos.bottom());
+
+ if(radius.bottom_left_x && radius.bottom_left_y)
+ {
+ add_path_arc(cr,
+ pos.left() + radius.bottom_left_x,
+ pos.bottom() - radius.bottom_left_y,
+ radius.bottom_left_x,
+ radius.bottom_left_y,
+ M_PI / 2.0,
+ M_PI, false);
+ }
+}
+
+cairo_surface_t* container_cairo::scale_surface(cairo_surface_t* surface, int width, int height)
+{
+ int s_width = cairo_image_surface_get_width(surface);
+ int s_height = cairo_image_surface_get_height(surface);
+ cairo_surface_t *result = cairo_surface_create_similar(surface, cairo_surface_get_content(surface), width, height);
+ cairo_t *cr = cairo_create(result);
+ cairo_scale(cr, (double) width / (double) s_width, (double) height / (double) s_height);
+ cairo_set_source_surface(cr, surface, 0, 0);
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint(cr);
+ cairo_destroy(cr);
+ return result;
+}
+
+void container_cairo::draw_pixbuf(cairo_t* cr, cairo_surface_t* bmp, int x, int y, int cx, int cy)
+{
+ cairo_save(cr);
+
+ {
+ cairo_matrix_t flip_m;
+ cairo_matrix_init(&flip_m, 1, 0, 0, -1, 0, 0);
+
+ if(cx != cairo_image_surface_get_width(bmp) || cy != cairo_image_surface_get_height(bmp))
+ {
+ auto bmp_scaled = scale_surface(bmp, cx, cy);
+ cairo_set_source_surface(cr, bmp_scaled, x, y);
+ cairo_paint(cr);
+ cairo_surface_destroy(bmp_scaled);
+ } else
+ {
+ cairo_set_source_surface(cr, bmp, x, y);
+ cairo_paint(cr);
+ }
+ }
+
+ cairo_restore(cr);
+}
+
+void container_cairo::get_media_features(litehtml::media_features& media) const
+{
+ litehtml::position client;
+ get_client_rect(client);
+ media.type = litehtml::media_type_screen;
+ media.width = client.width;
+ media.height = client.height;
+ media.device_width = get_screen_width();
+ media.device_height = get_screen_height();
+ media.color = 8;
+ media.monochrome = 0;
+ media.color_index = 256;
+ media.resolution = 96;
+}
+
+void container_cairo::get_language(litehtml::string& language, litehtml::string& culture) const
+{
+ language = "en";
+ culture = "";
+}
+
+void container_cairo::link(const std::shared_ptr<litehtml::document> &/*ptr*/, const litehtml::element::ptr& /*el*/)
+{
+
+}