summaryrefslogtreecommitdiff
path: root/libs/litehtml/containers/cairo
diff options
context:
space:
mode:
authorGeorge Hazan <george.hazan@gmail.com>2024-03-18 12:13:54 +0300
committerGeorge Hazan <george.hazan@gmail.com>2024-03-18 12:13:54 +0300
commit705c4d24c9c61edffc82864bf9c24384dc29a8d7 (patch)
tree4d21f87671db36b99402da3221d45b64c257c1fe /libs/litehtml/containers/cairo
parent5784fc3a62b9136c6690ed45ec7b505f35512e08 (diff)
litehtml - lightweight html renderer
Diffstat (limited to 'libs/litehtml/containers/cairo')
-rw-r--r--libs/litehtml/containers/cairo/cairo_borders.cpp342
-rw-r--r--libs/litehtml/containers/cairo/cairo_borders.h69
-rw-r--r--libs/litehtml/containers/cairo/cairo_images_cache.h91
-rw-r--r--libs/litehtml/containers/cairo/container_cairo.cpp539
-rw-r--r--libs/litehtml/containers/cairo/container_cairo.h88
-rw-r--r--libs/litehtml/containers/cairo/container_cairo_pango.cpp180
-rw-r--r--libs/litehtml/containers/cairo/container_cairo_pango.h37
7 files changed, 1346 insertions, 0 deletions
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 <litehtml.h>
+#include "cairo_borders.h"
+#include <cmath>
+
+#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);
+ }
+}
diff --git a/libs/litehtml/containers/cairo/cairo_borders.h b/libs/litehtml/containers/cairo/cairo_borders.h
new file mode 100644
index 0000000000..1bf18d6056
--- /dev/null
+++ b/libs/litehtml/containers/cairo/cairo_borders.h
@@ -0,0 +1,69 @@
+#ifndef LITEHTML_CAIRO_BORDERS_H
+#define LITEHTML_CAIRO_BORDERS_H
+
+#include <cairo.h>
+
+namespace cairo
+{
+ extern void add_path_arc(cairo_t* cr, double x, double y, double rx, double ry, double a1, double a2, bool neg);
+ inline void set_color(cairo_t* cr, const litehtml::web_color& color)
+ {
+ cairo_set_source_rgba(cr, color.red / 255.0, color.green / 255.0, color.blue / 255.0, color.alpha / 255.0);
+ }
+
+ class border
+ {
+ public:
+ enum real_side_t
+ {
+ left_side,
+ top_side,
+ right_side,
+ bottom_side
+ };
+
+ real_side_t real_side; /// real side of the border
+ litehtml::web_color color;
+ litehtml::border_style style;
+
+ int border_width;
+ int top_border_width;
+ int bottom_border_width;
+
+ int radius_top_x;
+ int radius_top_y;
+ int radius_bottom_x;
+ int radius_bottom_y;
+
+ border(cairo_t* _cr, int _left, int _top, int _bottom) :
+ real_side(left_side),
+ color(),
+ style(litehtml::border_style_none),
+ border_width(0),
+ top_border_width(0),
+ bottom_border_width(0),
+ radius_top_x(0),
+ radius_top_y(0),
+ radius_bottom_x(0),
+ radius_bottom_y(0),
+ cr(_cr), left(_left), top(_top), bottom(_bottom)
+ {}
+
+ void draw_border();
+
+ private:
+ cairo_t* cr;
+ int left;
+ int top;
+ int bottom;
+ void draw_line(double line_offset, double top_line_offset, double bottom_line_offset);
+ void draw_solid();
+ void draw_dotted();
+ void draw_dashed();
+ void draw_double();
+ void draw_inset_outset(bool is_inset);
+ void draw_groove_ridge(bool is_groove);
+ };
+}
+
+#endif //LITEHTML_CAIRO_BORDERS_H
diff --git a/libs/litehtml/containers/cairo/cairo_images_cache.h b/libs/litehtml/containers/cairo/cairo_images_cache.h
new file mode 100644
index 0000000000..4260fae2be
--- /dev/null
+++ b/libs/litehtml/containers/cairo/cairo_images_cache.h
@@ -0,0 +1,91 @@
+#ifndef LITEHTML_CAIRO_IMAGES_CACHE_H
+#define LITEHTML_CAIRO_IMAGES_CACHE_H
+
+#include <mutex>
+#include <map>
+#include <string>
+#include <cairo.h>
+
+class cairo_surface_wrapper
+{
+ cairo_surface_t* surface;
+public:
+ cairo_surface_wrapper() : surface(nullptr) {}
+ cairo_surface_wrapper(cairo_surface_wrapper& v) : surface(v.surface)
+ {
+ if(v.surface)
+ {
+ surface = cairo_surface_reference(v.surface);
+ }
+ }
+ explicit cairo_surface_wrapper(cairo_surface_t* v) : surface(v) {}
+ cairo_surface_wrapper(cairo_surface_wrapper&& v) noexcept
+ {
+ surface = v.surface;
+ v.surface = nullptr;
+ }
+ cairo_surface_wrapper& operator=(const cairo_surface_wrapper& v)
+ {
+ if(surface != v.surface)
+ {
+ if(surface)
+ {
+ cairo_surface_destroy(surface);
+ }
+ surface = cairo_surface_reference(v.surface);
+ }
+ return *this;
+ }
+ ~cairo_surface_wrapper()
+ {
+ if(surface)
+ {
+ cairo_surface_destroy(surface);
+ }
+ }
+ cairo_surface_t* get() { return cairo_surface_reference(surface); }
+};
+
+class cairo_images_cache
+{
+ std::mutex m_mutex;
+ std::map<std::string, cairo_surface_wrapper> m_images;
+public:
+ void add_image(const std::string& url, cairo_surface_t* image)
+ {
+ std::unique_lock<std::mutex> lock(m_mutex);
+ m_images[url] = cairo_surface_wrapper(image);
+ }
+
+ cairo_surface_t* get_image(const std::string& url)
+ {
+ std::unique_lock<std::mutex> lock(m_mutex);
+ auto iter = m_images.find(url);
+ if(iter != m_images.end())
+ {
+ return iter->second.get();
+ }
+ return nullptr;
+ }
+
+ bool reserve(const std::string& url)
+ {
+ std::unique_lock<std::mutex> lock(m_mutex);
+ auto iter = m_images.find(url);
+ if (iter == m_images.end())
+ {
+ m_images[url] = cairo_surface_wrapper();
+ return true;
+ }
+ return false;
+ }
+
+ bool exists(const std::string& url)
+ {
+ std::unique_lock<std::mutex> lock(m_mutex);
+ auto iter = m_images.find(url);
+ return iter != m_images.end();
+ }
+};
+
+#endif //LITEHTML_CAIRO_IMAGES_CACHE_H
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*/)
+{
+
+}
diff --git a/libs/litehtml/containers/cairo/container_cairo.h b/libs/litehtml/containers/cairo/container_cairo.h
new file mode 100644
index 0000000000..f5881a05db
--- /dev/null
+++ b/libs/litehtml/containers/cairo/container_cairo.h
@@ -0,0 +1,88 @@
+#ifndef LH_CONTAINER_LINUX_H
+#define LH_CONTAINER_LINUX_H
+
+#include "../../include/litehtml.h"
+#include <cairo.h>
+
+struct cairo_clip_box
+{
+ typedef std::vector<cairo_clip_box> vector;
+ litehtml::position box;
+ litehtml::border_radiuses radius;
+
+ cairo_clip_box(const litehtml::position& vBox, const litehtml::border_radiuses& vRad)
+ {
+ box = vBox;
+ radius = vRad;
+ }
+
+ cairo_clip_box(const cairo_clip_box& val)
+ {
+ box = val.box;
+ radius = val.radius;
+ }
+ cairo_clip_box& operator=(const cairo_clip_box& val)
+ {
+ box = val.box;
+ radius = val.radius;
+ return *this;
+ }
+};
+
+class container_cairo : public litehtml::document_container
+{
+protected:
+ cairo_clip_box::vector m_clips;
+public:
+ container_cairo() = default;
+ virtual ~container_cairo() = default;
+
+ int pt_to_px(int pt) const override;
+ int get_default_font_size() const override;
+ const char* get_default_font_name() const override;
+ void get_image_size(const char* src, const char* baseurl, litehtml::size& sz) override;
+ void draw_background(litehtml::uint_ptr hdc, const std::vector<litehtml::background_paint>& bg) override;
+ void draw_borders(litehtml::uint_ptr hdc, const litehtml::borders& borders, const litehtml::position& draw_pos, bool root) override;
+ void draw_list_marker(litehtml::uint_ptr hdc, const litehtml::list_marker& marker) override;
+ std::shared_ptr<litehtml::element> create_element(const char *tag_name,
+ const litehtml::string_map &attributes,
+ const std::shared_ptr<litehtml::document> &doc) override;
+ void get_media_features(litehtml::media_features& media) const override;
+ void get_language(litehtml::string& language, litehtml::string & culture) const override;
+ void link(const std::shared_ptr<litehtml::document> &ptr, const litehtml::element::ptr& el) override;
+
+
+ void transform_text(litehtml::string& text, litehtml::text_transform tt) override;
+ void set_clip(const litehtml::position& pos, const litehtml::border_radiuses& bdr_radius) override;
+ void del_clip() override;
+
+ virtual void make_url( const char* url, const char* basepath, litehtml::string& out );
+ virtual cairo_surface_t* get_image(const std::string& url) = 0;
+ virtual double get_screen_dpi() const = 0;
+ virtual int get_screen_width() const = 0;
+ virtual int get_screen_height() const = 0;
+
+ void clear_images();
+
+protected:
+ virtual void draw_ellipse(cairo_t* cr, int x, int y, int width, int height, const litehtml::web_color& color, int line_width);
+ virtual void fill_ellipse(cairo_t* cr, int x, int y, int width, int height, const litehtml::web_color& color);
+ virtual void rounded_rectangle( cairo_t* cr, const litehtml::position &pos, const litehtml::border_radiuses &radius );
+
+ void apply_clip(cairo_t* cr);
+ static void set_color(cairo_t* cr, const litehtml::web_color& color)
+ {
+ cairo_set_source_rgba(cr,
+ color.red / 255.0,
+ color.green / 255.0,
+ color.blue / 255.0,
+ color.alpha / 255.0);
+ }
+private:
+
+ static void add_path_arc(cairo_t* cr, double x, double y, double rx, double ry, double a1, double a2, bool neg);
+ static void draw_pixbuf(cairo_t* cr, cairo_surface_t* bmp, int x, int y, int cx, int cy);
+ static cairo_surface_t* scale_surface(cairo_surface_t* surface, int width, int height);
+};
+
+#endif
diff --git a/libs/litehtml/containers/cairo/container_cairo_pango.cpp b/libs/litehtml/containers/cairo/container_cairo_pango.cpp
new file mode 100644
index 0000000000..e218d7fd45
--- /dev/null
+++ b/libs/litehtml/containers/cairo/container_cairo_pango.cpp
@@ -0,0 +1,180 @@
+#include "container_cairo_pango.h"
+
+container_cairo_pango::container_cairo_pango()
+{
+ m_temp_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 2, 2);
+ m_temp_cr = cairo_create(m_temp_surface);
+}
+
+container_cairo_pango::~container_cairo_pango()
+{
+ clear_images();
+ cairo_surface_destroy(m_temp_surface);
+ cairo_destroy(m_temp_cr);
+}
+
+litehtml::uint_ptr container_cairo_pango::create_font(const char *faceName, int size, int weight, litehtml::font_style italic,
+ unsigned int decoration, litehtml::font_metrics *fm)
+{
+ PangoFontDescription *desc = pango_font_description_from_string (faceName);
+ pango_font_description_set_absolute_size(desc, size * PANGO_SCALE);
+ if(italic == litehtml::font_style_italic)
+ {
+ pango_font_description_set_style(desc, PANGO_STYLE_ITALIC);
+ } else
+ {
+ pango_font_description_set_style(desc, PANGO_STYLE_NORMAL);
+ }
+ PangoWeight fnt_weight;
+ if(weight >= 0 && weight < 150) fnt_weight = PANGO_WEIGHT_THIN;
+ else if(weight >= 150 && weight < 250) fnt_weight = PANGO_WEIGHT_ULTRALIGHT;
+ else if(weight >= 250 && weight < 350) fnt_weight = PANGO_WEIGHT_LIGHT;
+ else if(weight >= 350 && weight < 450) fnt_weight = PANGO_WEIGHT_NORMAL;
+ else if(weight >= 450 && weight < 550) fnt_weight = PANGO_WEIGHT_MEDIUM;
+ else if(weight >= 550 && weight < 650) fnt_weight = PANGO_WEIGHT_SEMIBOLD;
+ else if(weight >= 650 && weight < 750) fnt_weight = PANGO_WEIGHT_BOLD;
+ else if(weight >= 750 && weight < 850) fnt_weight = PANGO_WEIGHT_ULTRABOLD;
+ else fnt_weight = PANGO_WEIGHT_HEAVY;
+
+ pango_font_description_set_weight(desc, fnt_weight);
+
+ cairo_font* ret = nullptr;
+
+ if(fm)
+ {
+ cairo_save(m_temp_cr);
+ PangoLayout *layout = pango_cairo_create_layout(m_temp_cr);
+ PangoContext *context = pango_layout_get_context(layout);
+ PangoLanguage *language = pango_language_get_default();
+ pango_layout_set_font_description(layout, desc);
+ PangoFontMetrics *metrics = pango_context_get_metrics(context, desc, language);
+
+ fm->ascent = PANGO_PIXELS((double)pango_font_metrics_get_ascent(metrics));
+ fm->descent = PANGO_PIXELS((double)pango_font_metrics_get_descent(metrics));
+ fm->height = fm->ascent + fm->descent;
+ fm->x_height = fm->height;
+
+ pango_layout_set_text(layout, "x", 1);
+
+ int x_width, x_height;
+ pango_layout_get_pixel_size(layout, &x_width, &x_height);
+
+ fm->x_height = x_height;
+
+ cairo_restore(m_temp_cr);
+
+ g_object_unref(layout);
+ pango_font_metrics_unref(metrics);
+
+ ret = new cairo_font;
+ ret->font = desc;
+ ret->size = size;
+ ret->strikeout = (decoration & litehtml::font_decoration_linethrough) != 0;
+ ret->underline = (decoration & litehtml::font_decoration_underline) != 0;
+ ret->ascent = fm->ascent;
+ ret->descent = fm->descent;
+
+ ret->underline_thickness = pango_font_metrics_get_underline_thickness(metrics);
+ ret->underline_position = -pango_font_metrics_get_underline_position(metrics);
+ pango_quantize_line_geometry(&ret->underline_thickness, &ret->underline_position);
+ ret->underline_thickness = PANGO_PIXELS(ret->underline_thickness);
+ ret->underline_position = -1;//PANGO_PIXELS(ret->underline_position);
+
+ ret->strikethrough_thickness = pango_font_metrics_get_strikethrough_thickness(metrics);
+ ret->strikethrough_position = pango_font_metrics_get_strikethrough_position(metrics);
+ pango_quantize_line_geometry(&ret->strikethrough_thickness, &ret->strikethrough_position);
+ ret->strikethrough_thickness = PANGO_PIXELS(ret->strikethrough_thickness);
+ ret->strikethrough_position = PANGO_PIXELS(ret->strikethrough_position);
+ }
+
+ return (litehtml::uint_ptr) ret;
+}
+
+void container_cairo_pango::delete_font(litehtml::uint_ptr hFont)
+{
+ auto* fnt = (cairo_font*) hFont;
+ if(fnt)
+ {
+ pango_font_description_free(fnt->font);
+ delete fnt;
+ }
+}
+
+int container_cairo_pango::text_width(const char *text, litehtml::uint_ptr hFont)
+{
+ auto* fnt = (cairo_font*) hFont;
+
+ cairo_save(m_temp_cr);
+
+ PangoLayout *layout = pango_cairo_create_layout(m_temp_cr);
+ pango_layout_set_font_description(layout, fnt->font);
+
+ pango_layout_set_text(layout, text, -1);
+ pango_cairo_update_layout (m_temp_cr, layout);
+
+ int x_width, x_height;
+ pango_layout_get_pixel_size(layout, &x_width, &x_height);
+
+ cairo_restore(m_temp_cr);
+
+ g_object_unref(layout);
+
+ return (int) x_width;
+}
+
+void container_cairo_pango::draw_text(litehtml::uint_ptr hdc, const char *text, litehtml::uint_ptr hFont,
+ litehtml::web_color color, const litehtml::position &pos)
+{
+ auto* fnt = (cairo_font*) hFont;
+ auto* cr = (cairo_t*) hdc;
+ cairo_save(cr);
+
+ apply_clip(cr);
+
+ set_color(cr, color);
+
+ PangoLayout *layout = pango_cairo_create_layout(cr);
+ pango_layout_set_font_description (layout, fnt->font);
+ pango_layout_set_text (layout, text, -1);
+
+ int baseline = PANGO_PIXELS(pango_layout_get_baseline(layout));
+
+ PangoRectangle ink_rect, logical_rect;
+ pango_layout_get_pixel_extents(layout, &ink_rect, &logical_rect);
+
+ int text_baseline = pos.height - fnt->descent;
+
+ int x = pos.left() + logical_rect.x;
+ int y = pos.top() + logical_rect.y + text_baseline - baseline;
+
+ cairo_move_to(cr, x, y);
+ pango_cairo_update_layout (cr, layout);
+ pango_cairo_show_layout (cr, layout);
+
+ int tw = 0;
+
+ if(fnt->underline || fnt->strikeout)
+ {
+ tw = text_width(text, hFont);
+ }
+
+ if(fnt->underline)
+ {
+ cairo_set_line_width(cr, fnt->underline_thickness);
+ cairo_move_to(cr, x, pos.top() + text_baseline - fnt->underline_position + 0.5);
+ cairo_line_to(cr, x + tw, pos.top() + text_baseline - fnt->underline_position + 0.5);
+ cairo_stroke(cr);
+ }
+ if(fnt->strikeout)
+ {
+ cairo_set_line_width(cr, fnt->strikethrough_thickness);
+ cairo_move_to(cr, x, pos.top() + text_baseline - fnt->strikethrough_position - 0.5);
+ cairo_line_to(cr, x + tw, pos.top() + text_baseline - fnt->strikethrough_position - 0.5);
+ cairo_stroke(cr);
+ }
+
+ cairo_restore(cr);
+
+ g_object_unref(layout);
+}
+
diff --git a/libs/litehtml/containers/cairo/container_cairo_pango.h b/libs/litehtml/containers/cairo/container_cairo_pango.h
new file mode 100644
index 0000000000..455bcf5cfb
--- /dev/null
+++ b/libs/litehtml/containers/cairo/container_cairo_pango.h
@@ -0,0 +1,37 @@
+#ifndef LITEBROWSER_CONTAINER_CAIRO_PANGO_H
+#define LITEBROWSER_CONTAINER_CAIRO_PANGO_H
+
+#include <litehtml.h>
+#include "container_cairo.h"
+#include <cairo.h>
+#include <pango/pangocairo.h>
+#include <pango/pango-font.h>
+
+struct cairo_font
+{
+ PangoFontDescription* font;
+ int size;
+ bool underline;
+ bool strikeout;
+ int ascent;
+ int descent;
+ int underline_thickness;
+ int underline_position;
+ int strikethrough_thickness;
+ int strikethrough_position;
+};
+
+class container_cairo_pango : public container_cairo
+{
+ cairo_surface_t* m_temp_surface;
+ cairo_t* m_temp_cr;
+public:
+ container_cairo_pango();
+ ~container_cairo_pango() override;
+ litehtml::uint_ptr create_font(const char* faceName, int size, int weight, litehtml::font_style italic, unsigned int decoration, litehtml::font_metrics* fm) override;
+ void delete_font(litehtml::uint_ptr hFont) override;
+ int text_width(const char* text, litehtml::uint_ptr hFont) override;
+ void draw_text(litehtml::uint_ptr hdc, const char* text, litehtml::uint_ptr hFont, litehtml::web_color color, const litehtml::position& pos) override;
+};
+
+#endif //LITEBROWSER_CONTAINER_CAIRO_PANGO_H