X-Git-Url: http://git.claws-mail.org/?p=claws.git;a=blobdiff_plain;f=src%2Fplugins%2Flitehtml_viewer%2Fcontainer_linux.cpp;h=ac0f40e0e8651a81a01a6502a9fabfc9a5a68d98;hp=923ce769f7238e23b0e604f89954459f4ef8b8f3;hb=HEAD;hpb=ce18d1ccbcde0bac5e01f4b3c2a07740226bfeb1;ds=sidebyside diff --git a/src/plugins/litehtml_viewer/container_linux.cpp b/src/plugins/litehtml_viewer/container_linux.cpp index 923ce769f..19d226202 100644 --- a/src/plugins/litehtml_viewer/container_linux.cpp +++ b/src/plugins/litehtml_viewer/container_linux.cpp @@ -1,5 +1,5 @@ /* - * Claws Mail -- A GTK+ based, lightweight, and fast e-mail client + * Claws Mail -- A GTK based, lightweight, and fast e-mail client * Copyright(C) 2019 the Claws Mail Team * * This program is free software; you can redistribute it and/or modify @@ -21,24 +21,24 @@ #endif #include "container_linux.h" +#include "container_linux_images.h" -#include - -#define _USE_MATH_DEFINES -#include +#include +#include "lh_prefs.h" +#include "utils.h" #ifndef M_PI # define M_PI 3.14159265358979323846 #endif -container_linux::container_linux(void) +container_linux::container_linux() { m_temp_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 2, 2); m_temp_cr = cairo_create(m_temp_surface); g_rec_mutex_init(&m_images_lock); } -container_linux::~container_linux(void) +container_linux::~container_linux() { clear_images(); cairo_surface_destroy(m_temp_surface); @@ -46,7 +46,170 @@ container_linux::~container_linux(void) g_rec_mutex_clear(&m_images_lock); } -int container_linux::pt_to_px( int pt ) +litehtml::uint_ptr container_linux::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_linux::delete_font( litehtml::uint_ptr hFont ) +{ + auto* fnt = (cairo_font*) hFont; + if(fnt) + { + pango_font_description_free(fnt->font); + delete fnt; + } +} + +int container_linux::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_linux::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); +} + +int container_linux::pt_to_px( int pt ) const { GdkScreen* screen = gdk_screen_get_default(); double dpi = gdk_screen_get_resolution(screen); @@ -54,11 +217,18 @@ int container_linux::pt_to_px( int pt ) return (int) ((double) pt * dpi / 72.0); } +/* +int container_linux::get_default_font_size() const +{ + return pt_to_px(12); +} +*/ + void container_linux::draw_list_marker( litehtml::uint_ptr hdc, const litehtml::list_marker& marker ) { if(!marker.image.empty()) { - /*litehtml::tstring url; + /*litehtml::string url; make_url(marker.image.c_str(), marker.baseurl, url); lock_images_cache(); @@ -77,7 +247,7 @@ void container_linux::draw_list_marker( litehtml::uint_ptr hdc, const litehtml:: { 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, 0.5); + 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: @@ -88,7 +258,7 @@ void container_linux::draw_list_marker( litehtml::uint_ptr hdc, const litehtml:: case litehtml::list_style_type_square: if(hdc) { - cairo_t* cr = (cairo_t*) hdc; + auto* cr = (cairo_t*) hdc; cairo_save(cr); cairo_new_path(cr); @@ -106,12 +276,96 @@ void container_linux::draw_list_marker( litehtml::uint_ptr hdc, const litehtml:: } } -void container_linux::draw_background( litehtml::uint_ptr hdc, const litehtml::background_paint& bg ) +void container_linux::load_image( const char* src, const char* baseurl, bool redraw_on_ready ) +{ + litehtml::string url; + make_url(src, baseurl, url); + bool request = false; + struct timeval last; + + gettimeofday(&last, NULL); + + lock_images_cache(); + + auto i = m_images.find(url); + if(i == m_images.end()) { + /* Attached images can be loaded into cache right here. */ + if (!strncmp(src, "cid:", 4)) { + GdkPixbuf *pixbuf = get_local_image(src); + + if (pixbuf != NULL) + m_images.insert(std::make_pair(src, std::make_pair(pixbuf, last))); + + unlock_images_cache(); + return; + } else { + if (!lh_prefs_get()->enable_remote_content) { + debug_print("blocking download of image from '%s'\n", src); + unlock_images_cache(); + return; + } + + request = true; + m_images.insert(std::make_pair(url, std::make_pair((GdkPixbuf *)NULL, last))); + } + } else { + debug_print("found image cache entry: %p '%s'\n", i->second.first, url.c_str()); + i->second.second = last; + } + + unlock_images_cache(); + + if (request) { + struct FetchCtx *ctx; + + debug_print("allowing download of image from '%s'\n", src); + + ctx = g_new(struct FetchCtx, 1); + ctx->url = g_strdup(url.c_str()); + ctx->container = this; + + GTask *task = g_task_new(NULL, NULL, get_image_callback, ctx); + g_task_set_task_data(task, ctx, NULL); + g_task_run_in_thread(task, get_image_threaded); + } +} + +void container_linux::get_image_size( const char* src, const char* baseurl, litehtml::size& sz ) +{ + litehtml::string url; + make_url(src, baseurl, url); + + lock_images_cache(); + + auto img = m_images.find(url); + if(img != m_images.end()) + { + if(img->second.first) + { + sz.width = gdk_pixbuf_get_width(img->second.first); + sz.height = gdk_pixbuf_get_height(img->second.first); + } else + { + sz.width = 0; + sz.height = 0; + } + } else + { + sz.width = 0; + sz.height = 0; + } + + unlock_images_cache(); +} + +void container_linux::draw_background( litehtml::uint_ptr hdc, const std::vector& bgvec ) { - cairo_t* cr = (cairo_t*) hdc; + 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); @@ -124,76 +378,78 @@ void container_linux::draw_background( litehtml::uint_ptr hdc, const litehtml::b cairo_paint(cr); } - litehtml::tstring url; - make_url(bg.image.c_str(), bg.baseurl.c_str(), url); + for (int i = (int)bgvec.size() - 1; i >= 0; i--) + { + const auto& bg = bgvec[i]; - lock_images_cache(); - bool found = false; - const image *img_i = NULL; - - for (auto ii = m_images.cbegin(); ii != m_images.cend(); ++ii) { - const image *i = &(*ii); - if (i->first == url) { - img_i = i; - found = true; - break; - } - } + if(bg.image_size.height == 0 || bg.image_size.width == 0) continue; - if(img_i != NULL && img_i->second) - { - GdkPixbuf *bgbmp = img_i->second; + 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); - GdkPixbuf *new_img; - if(bg.image_size.width != gdk_pixbuf_get_width(bgbmp) || bg.image_size.height != gdk_pixbuf_get_height(bgbmp)) + lock_images_cache(); + auto img_i = m_images.find(url); + if(img_i != m_images.end() && img_i->second.first) { - new_img = gdk_pixbuf_scale_simple(bgbmp, bg.image_size.width, bg.image_size.height, GDK_INTERP_BILINEAR); - bgbmp = new_img; - } + GdkPixbuf *bgbmp = img_i->second.first; - cairo_surface_t* img = surface_from_pixbuf(bgbmp); - cairo_pattern_t *pattern = cairo_pattern_create_for_surface(img); - 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); + GdkPixbuf *new_img = NULL; + if(bg.image_size.width != gdk_pixbuf_get_width(bgbmp) || bg.image_size.height != gdk_pixbuf_get_height(bgbmp)) + { + new_img = gdk_pixbuf_scale_simple(bgbmp, bg.image_size.width, bg.image_size.height, GDK_INTERP_BILINEAR); + bgbmp = new_img; + } - switch(bg.repeat) - { - case litehtml::background_repeat_no_repeat: - draw_pixbuf(cr, bgbmp, bg.position_x, bg.position_y, gdk_pixbuf_get_width(bgbmp), gdk_pixbuf_get_height(bgbmp)); - break; + cairo_surface_t* img = surface_from_pixbuf(bgbmp); + cairo_pattern_t *pattern = cairo_pattern_create_for_surface(img); + 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); - 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, gdk_pixbuf_get_height(bgbmp)); - cairo_fill(cr); - break; + switch(bg.repeat) + { + case litehtml::background_repeat_no_repeat: + draw_pixbuf(cr, bgbmp, bg.position_x, bg.position_y, gdk_pixbuf_get_width(bgbmp), gdk_pixbuf_get_height(bgbmp)); + break; - case litehtml::background_repeat_repeat_y: - cairo_set_source(cr, pattern); - cairo_rectangle(cr, bg.position_x, bg.clip_box.top(), gdk_pixbuf_get_width(bgbmp), bg.clip_box.height); - cairo_fill(cr); - 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, gdk_pixbuf_get_height(bgbmp)); + 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; - } + case litehtml::background_repeat_repeat_y: + cairo_set_source(cr, pattern); + cairo_rectangle(cr, bg.position_x, bg.clip_box.top(), gdk_pixbuf_get_width(bgbmp), bg.clip_box.height); + cairo_fill(cr); + break; - cairo_pattern_destroy(pattern); - cairo_surface_destroy(img); + 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(img); + if(new_img) + { + g_object_unref(new_img); + } + } + unlock_images_cache(); } - unlock_images_cache(); cairo_restore(cr); } -void container_linux::make_url(const litehtml::tchar_t* url, const litehtml::tchar_t* basepath, litehtml::tstring& out) +void container_linux::make_url(const char* url, const char* basepath, litehtml::string& out) { out = url; } @@ -226,7 +482,7 @@ void container_linux::add_path_arc(cairo_t* cr, double x, double y, double rx, d void container_linux::draw_borders(litehtml::uint_ptr hdc, const litehtml::borders& borders, const litehtml::position& draw_pos, bool root) { - cairo_t* cr = (cairo_t*) hdc; + auto* cr = (cairo_t*) hdc; cairo_save(cr); apply_clip(cr); @@ -259,57 +515,54 @@ void container_linux::draw_borders(litehtml::uint_ptr hdc, const litehtml::borde { set_color(cr, borders.right.color); - double r_top = borders.radius.top_right_x; - double r_bottom = borders.radius.bottom_right_x; - - if(r_top) + if(borders.radius.top_right_x && borders.radius.top_right_y) { double end_angle = 2 * M_PI; double start_angle = end_angle - M_PI / 2.0 / ((double) bdr_top / (double) bdr_right + 1); add_path_arc(cr, - draw_pos.right() - r_top, - draw_pos.top() + r_top, - r_top - bdr_right, - r_top - bdr_right + (bdr_right - bdr_top), - end_angle, - start_angle, true); + draw_pos.right() - borders.radius.top_right_x, + draw_pos.top() + borders.radius.top_right_y, + borders.radius.top_right_x - bdr_right, + borders.radius.top_right_y - bdr_right + (bdr_right - bdr_top), + end_angle, + start_angle, true); add_path_arc(cr, - draw_pos.right() - r_top, - draw_pos.top() + r_top, - r_top, - r_top, - start_angle, - end_angle, false); + draw_pos.right() - borders.radius.top_right_x, + draw_pos.top() + borders.radius.top_right_y, + borders.radius.top_right_x, + borders.radius.top_right_y, + start_angle, + end_angle, false); } else { cairo_move_to(cr, draw_pos.right() - bdr_right, draw_pos.top() + bdr_top); cairo_line_to(cr, draw_pos.right(), draw_pos.top()); } - if(r_bottom) + if(borders.radius.bottom_right_x && borders.radius.bottom_right_y) { - cairo_line_to(cr, draw_pos.right(), draw_pos.bottom() - r_bottom); + cairo_line_to(cr, draw_pos.right(), draw_pos.bottom() - borders.radius.bottom_right_y); double start_angle = 0; double end_angle = start_angle + M_PI / 2.0 / ((double) bdr_bottom / (double) bdr_right + 1); add_path_arc(cr, - draw_pos.right() - r_bottom, - draw_pos.bottom() - r_bottom, - r_bottom, - r_bottom, - start_angle, - end_angle, false); + draw_pos.right() - borders.radius.bottom_right_x, + draw_pos.bottom() - borders.radius.bottom_right_y, + borders.radius.bottom_right_x, + borders.radius.bottom_right_y, + start_angle, + end_angle, false); add_path_arc(cr, - draw_pos.right() - r_bottom, - draw_pos.bottom() - r_bottom, - r_bottom - bdr_right, - r_bottom - bdr_right + (bdr_right - bdr_bottom), - end_angle, - start_angle, true); + draw_pos.right() - borders.radius.bottom_right_x, + draw_pos.bottom() - borders.radius.bottom_right_y, + borders.radius.bottom_right_x - bdr_right, + borders.radius.bottom_right_y - bdr_right + (bdr_right - bdr_bottom), + end_angle, + start_angle, true); } else { cairo_line_to(cr, draw_pos.right(), draw_pos.bottom()); @@ -324,57 +577,54 @@ void container_linux::draw_borders(litehtml::uint_ptr hdc, const litehtml::borde { set_color(cr, borders.bottom.color); - double r_left = borders.radius.bottom_left_x; - double r_right = borders.radius.bottom_right_x; - - if(r_left) + if(borders.radius.bottom_left_x && borders.radius.bottom_left_y) { double start_angle = M_PI / 2.0; double end_angle = start_angle + M_PI / 2.0 / ((double) bdr_left / (double) bdr_bottom + 1); add_path_arc(cr, - draw_pos.left() + r_left, - draw_pos.bottom() - r_left, - r_left - bdr_bottom + (bdr_bottom - bdr_left), - r_left - bdr_bottom, - start_angle, - end_angle, false); + draw_pos.left() + borders.radius.bottom_left_x, + draw_pos.bottom() - borders.radius.bottom_left_y, + borders.radius.bottom_left_x - bdr_bottom + (bdr_bottom - bdr_left), + borders.radius.bottom_left_y - bdr_bottom, + start_angle, + end_angle, false); add_path_arc(cr, - draw_pos.left() + r_left, - draw_pos.bottom() - r_left, - r_left, - r_left, - end_angle, - start_angle, true); + draw_pos.left() + borders.radius.bottom_left_x, + draw_pos.bottom() - borders.radius.bottom_left_y, + borders.radius.bottom_left_x, + borders.radius.bottom_left_y, + end_angle, + start_angle, true); } else { cairo_move_to(cr, draw_pos.left(), draw_pos.bottom()); cairo_line_to(cr, draw_pos.left() + bdr_left, draw_pos.bottom() - bdr_bottom); } - if(r_right) + if(borders.radius.bottom_right_x && borders.radius.bottom_right_y) { - cairo_line_to(cr, draw_pos.right() - r_right, draw_pos.bottom()); + cairo_line_to(cr, draw_pos.right() - borders.radius.bottom_right_x, draw_pos.bottom()); double end_angle = M_PI / 2.0; double start_angle = end_angle - M_PI / 2.0 / ((double) bdr_right / (double) bdr_bottom + 1); add_path_arc(cr, - draw_pos.right() - r_right, - draw_pos.bottom() - r_right, - r_right, - r_right, - end_angle, - start_angle, true); + draw_pos.right() - borders.radius.bottom_right_x, + draw_pos.bottom() - borders.radius.bottom_right_y, + borders.radius.bottom_right_x, + borders.radius.bottom_right_y, + end_angle, + start_angle, true); add_path_arc(cr, - draw_pos.right() - r_right, - draw_pos.bottom() - r_right, - r_right - bdr_bottom + (bdr_bottom - bdr_right), - r_right - bdr_bottom, - start_angle, - end_angle, false); + draw_pos.right() - borders.radius.bottom_right_x, + draw_pos.bottom() - borders.radius.bottom_right_y, + borders.radius.bottom_right_x - bdr_bottom + (bdr_bottom - bdr_right), + borders.radius.bottom_right_y - bdr_bottom, + start_angle, + end_angle, false); } else { cairo_line_to(cr, draw_pos.right() - bdr_right, draw_pos.bottom() - bdr_bottom); @@ -389,57 +639,54 @@ void container_linux::draw_borders(litehtml::uint_ptr hdc, const litehtml::borde { set_color(cr, borders.top.color); - double r_left = borders.radius.top_left_x; - double r_right = borders.radius.top_right_x; - - if(r_left) + if(borders.radius.top_left_x && borders.radius.top_left_y) { double end_angle = M_PI * 3.0 / 2.0; double start_angle = end_angle - M_PI / 2.0 / ((double) bdr_left / (double) bdr_top + 1); add_path_arc(cr, - draw_pos.left() + r_left, - draw_pos.top() + r_left, - r_left, - r_left, - end_angle, - start_angle, true); + draw_pos.left() + borders.radius.top_left_x, + draw_pos.top() + borders.radius.top_left_y, + borders.radius.top_left_x, + borders.radius.top_left_y, + end_angle, + start_angle, true); add_path_arc(cr, - draw_pos.left() + r_left, - draw_pos.top() + r_left, - r_left - bdr_top + (bdr_top - bdr_left), - r_left - bdr_top, - start_angle, - end_angle, false); + draw_pos.left() + borders.radius.top_left_x, + draw_pos.top() + borders.radius.top_left_y, + borders.radius.top_left_x - bdr_top + (bdr_top - bdr_left), + borders.radius.top_left_y - bdr_top, + start_angle, + end_angle, false); } else { cairo_move_to(cr, draw_pos.left(), draw_pos.top()); cairo_line_to(cr, draw_pos.left() + bdr_left, draw_pos.top() + bdr_top); } - if(r_right) + if(borders.radius.top_right_x && borders.radius.top_right_y) { - cairo_line_to(cr, draw_pos.right() - r_right, draw_pos.top() + bdr_top); + cairo_line_to(cr, draw_pos.right() - borders.radius.top_right_x, draw_pos.top() + bdr_top); double start_angle = M_PI * 3.0 / 2.0; double end_angle = start_angle + M_PI / 2.0 / ((double) bdr_right / (double) bdr_top + 1); add_path_arc(cr, - draw_pos.right() - r_right, - draw_pos.top() + r_right, - r_right - bdr_top + (bdr_top - bdr_right), - r_right - bdr_top, - start_angle, - end_angle, false); + draw_pos.right() - borders.radius.top_right_x, + draw_pos.top() + borders.radius.top_right_y, + borders.radius.top_right_x - bdr_top + (bdr_top - bdr_right), + borders.radius.top_right_y - bdr_top, + start_angle, + end_angle, false); add_path_arc(cr, - draw_pos.right() - r_right, - draw_pos.top() + r_right, - r_right, - r_right, - end_angle, - start_angle, true); + draw_pos.right() - borders.radius.top_right_x, + draw_pos.top() + borders.radius.top_right_y, + borders.radius.top_right_x, + borders.radius.top_right_y, + end_angle, + start_angle, true); } else { cairo_line_to(cr, draw_pos.right() - bdr_right, draw_pos.top() + bdr_top); @@ -454,57 +701,54 @@ void container_linux::draw_borders(litehtml::uint_ptr hdc, const litehtml::borde { set_color(cr, borders.left.color); - double r_top = borders.radius.top_left_x; - double r_bottom = borders.radius.bottom_left_x; - - if(r_top) + if(borders.radius.top_left_x && borders.radius.top_left_y) { double start_angle = M_PI; double end_angle = start_angle + M_PI / 2.0 / ((double) bdr_top / (double) bdr_left + 1); add_path_arc(cr, - draw_pos.left() + r_top, - draw_pos.top() + r_top, - r_top - bdr_left, - r_top - bdr_left + (bdr_left - bdr_top), - start_angle, - end_angle, false); + draw_pos.left() + borders.radius.top_left_x, + draw_pos.top() + borders.radius.top_left_y, + borders.radius.top_left_x - bdr_left, + borders.radius.top_left_y - bdr_left + (bdr_left - bdr_top), + start_angle, + end_angle, false); add_path_arc(cr, - draw_pos.left() + r_top, - draw_pos.top() + r_top, - r_top, - r_top, - end_angle, - start_angle, true); + draw_pos.left() + borders.radius.top_left_x, + draw_pos.top() + borders.radius.top_left_y, + borders.radius.top_left_x, + borders.radius.top_left_y, + end_angle, + start_angle, true); } else { cairo_move_to(cr, draw_pos.left() + bdr_left, draw_pos.top() + bdr_top); cairo_line_to(cr, draw_pos.left(), draw_pos.top()); } - if(r_bottom) + if(borders.radius.bottom_left_x && borders.radius.bottom_left_y) { - cairo_line_to(cr, draw_pos.left(), draw_pos.bottom() - r_bottom); + cairo_line_to(cr, draw_pos.left(), draw_pos.bottom() - borders.radius.bottom_left_y); double end_angle = M_PI; double start_angle = end_angle - M_PI / 2.0 / ((double) bdr_bottom / (double) bdr_left + 1); add_path_arc(cr, - draw_pos.left() + r_bottom, - draw_pos.bottom() - r_bottom, - r_bottom, - r_bottom, - end_angle, - start_angle, true); + draw_pos.left() + borders.radius.bottom_left_x, + draw_pos.bottom() - borders.radius.bottom_left_y, + borders.radius.bottom_left_x, + borders.radius.bottom_left_y, + end_angle, + start_angle, true); add_path_arc(cr, - draw_pos.left() + r_bottom, - draw_pos.bottom() - r_bottom, - r_bottom - bdr_left, - r_bottom - bdr_left + (bdr_left - bdr_bottom), - start_angle, - end_angle, false); + draw_pos.left() + borders.radius.bottom_left_x, + draw_pos.bottom() - borders.radius.bottom_left_y, + borders.radius.bottom_left_x - bdr_left, + borders.radius.bottom_left_y - bdr_left + (bdr_left - bdr_bottom), + start_angle, + end_angle, false); } else { cairo_line_to(cr, draw_pos.left(), draw_pos.bottom()); @@ -516,27 +760,14 @@ void container_linux::draw_borders(litehtml::uint_ptr hdc, const litehtml::borde cairo_restore(cr); } -void container_linux::transform_text(litehtml::tstring& text, litehtml::text_transform tt) +void container_linux::transform_text(litehtml::string& text, litehtml::text_transform tt) { } -void container_linux::set_clip( const litehtml::position& pos, const litehtml::border_radiuses& bdr_radius, bool valid_x, bool valid_y ) +void container_linux::set_clip( const litehtml::position& pos, const litehtml::border_radiuses& bdr_radius ) { - litehtml::position clip_pos = pos; - litehtml::position client_pos; - get_client_rect(client_pos); - if(!valid_x) - { - clip_pos.x = client_pos.x; - clip_pos.width = client_pos.width; - } - if(!valid_y) - { - clip_pos.y = client_pos.y; - clip_pos.height = client_pos.height; - } - m_clips.emplace_back(clip_pos, bdr_radius); + m_clips.emplace_back(pos, bdr_radius); } void container_linux::del_clip() @@ -558,7 +789,7 @@ void container_linux::apply_clip( cairo_t* cr ) void container_linux::draw_ellipse( cairo_t* cr, int x, int y, int width, int height, const litehtml::web_color& color, int line_width ) { - if(!cr) return; + if(!cr || !width || !height) return; cairo_save(cr); apply_clip(cr); @@ -578,7 +809,7 @@ void container_linux::draw_ellipse( cairo_t* cr, int x, int y, int width, int he void container_linux::fill_ellipse( cairo_t* cr, int x, int y, int width, int height, const litehtml::web_color& color ) { - if(!cr) return; + if(!cr || !width || !height) return; cairo_save(cr); apply_clip(cr); @@ -595,19 +826,119 @@ void container_linux::fill_ellipse( cairo_t* cr, int x, int y, int width, int he cairo_restore(cr); } -std::shared_ptr container_linux::create_element(const litehtml::tchar_t *tag_name, +void container_linux::clear_images() +{ + lock_images_cache(); + + for(auto i = m_images.begin(); i != m_images.end(); ++i) { + if (i->second.first) { + g_object_unref(i->second.first); + } + } + + m_images.clear(); + + unlock_images_cache(); +} + +gint container_linux::clear_images(gsize desired_size) +{ + gsize size = 0; + gint num = 0; + + lock_images_cache(); + + /* First, remove all local images - the ones with "cid:" URL. */ + for (auto i = m_images.begin(); i != m_images.end(); ) { + if (!strncmp(i->first.c_str(), "cid:", 4)) { + g_object_unref(i->second.first); + i = m_images.erase(i); + num++; + } else { + ++i; + } + } + + /* Second, build an LRU list */ + auto lru_comp_func = [](const lru_entry& l1, const lru_entry& l2) { + return timercmp(&l1.second, &l2.second, <); + }; + std::set lru(lru_comp_func); + + for (auto i = m_images.begin(); i != m_images.end(); ++i) { + lru.insert(std::make_pair(i->first, i->second.second)); + } + + /* + for (auto l = lru.begin(); l != lru.end(); l++) { + debug_print("lru dump: %d %d %s\n", l->second.tv_sec, l->second.tv_usec, l->first.c_str()); + } + */ + + /* Last, walk the LRU list and remove the oldest entries that push it over + * the desired size limit */ + for (auto l = lru.rbegin(); l != lru.rend(); ++l) { + gsize cursize; + + auto i = m_images.find(l->first); + + if(i == m_images.end()) { + g_warning("failed to find '%s' in m_images", l->first.c_str()); + continue; + } + + if(i->second.first == NULL) { + /* This should mean that the download is still in progress */ + debug_print("warning - trying to prune a null pixbuf for %s\n", i->first.c_str()); + continue; + } + + cursize = gdk_pixbuf_get_byte_length(i->second.first); + /* + debug_print("clear_images: desired_size %d - size %d - cursize %d - %d %d %s\n", + desired_size, size, cursize, l->second.tv_sec, l->second.tv_usec, l->first.c_str()); + */ + if (size + cursize > desired_size) { + debug_print("pruning %s from image cache\n", i->first.c_str()); + g_object_unref(i->second.first); + m_images.erase(i); + num++; + } else { + size += cursize; + } + } + + unlock_images_cache(); + + return num; +} + +/* +const char* container_linux::get_default_font_name() const +{ + return "Times New Roman"; +} +*/ + +std::shared_ptr container_linux::create_element(const char *tag_name, const litehtml::string_map &attributes, const std::shared_ptr &doc) { - return 0; + return nullptr; } void container_linux::rounded_rectangle( cairo_t* cr, const litehtml::position &pos, const litehtml::border_radiuses &radius ) { cairo_new_path(cr); - if(radius.top_left_x) + if(radius.top_left_x && radius.top_left_y) { - cairo_arc(cr, pos.left() + radius.top_left_x, pos.top() + radius.top_left_x, radius.top_left_x, M_PI, M_PI * 3.0 / 2.0); + 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()); @@ -615,23 +946,41 @@ void container_linux::rounded_rectangle( cairo_t* cr, const litehtml::position & cairo_line_to(cr, pos.right() - radius.top_right_x, pos.top()); - if(radius.top_right_x) + if(radius.top_right_x && radius.top_right_y) { - cairo_arc(cr, pos.right() - radius.top_right_x, pos.top() + radius.top_right_x, radius.top_right_x, M_PI * 3.0 / 2.0, 2.0 * M_PI); + 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) + if(radius.bottom_right_x && radius.bottom_right_y) { - cairo_arc(cr, pos.right() - radius.bottom_right_x, pos.bottom() - radius.bottom_right_x, radius.bottom_right_x, 0, M_PI / 2.0); + 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) + if(radius.bottom_left_x && radius.bottom_left_y) { - cairo_arc(cr, pos.left() + radius.bottom_left_x, pos.bottom() - radius.bottom_left_x, radius.bottom_left_x, M_PI / 2.0, M_PI); + 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); } } @@ -660,7 +1009,7 @@ void container_linux::draw_pixbuf(cairo_t* cr, const GdkPixbuf *bmp, int x, int cairo_surface_t* container_linux::surface_from_pixbuf(const GdkPixbuf *bmp) { - cairo_surface_t* ret = NULL; + cairo_surface_t* ret; if(gdk_pixbuf_get_has_alpha(bmp)) { @@ -695,10 +1044,10 @@ void container_linux::get_media_features(litehtml::media_features& media) const media.resolution = 96; } -void container_linux::get_language(litehtml::tstring& language, litehtml::tstring& culture) const +void container_linux::get_language(litehtml::string& language, litehtml::string& culture) const { - language = _t("en"); - culture = _t(""); + language = "en"; + culture = ""; } void container_linux::link(const std::shared_ptr &ptr, const litehtml::element::ptr& el)