/*
- * Claws Mail -- A GTK+ based, lightweight, and fast e-mail client
- * Copyright(C) 1999-2015 the Claws Mail Team
- * == Fancy Plugin ==
- * This file Copyright (C) 2009-2015 Salvatore De Paolis
- * <iwkse@claws-mail.org> and the Claws Mail Team
+ * 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
#endif
#include "container_linux.h"
+#include "container_linux_images.h"
-#include <cairo-ft.h>
-
-#define _USE_MATH_DEFINES
-#include <math.h>
+#include <cmath>
+#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);
cairo_destroy(m_temp_cr);
+ g_rec_mutex_clear(&m_images_lock);
}
-litehtml::uint_ptr container_linux::create_font( const litehtml::tchar_t* faceName, int size, int weight, litehtml::font_style italic, unsigned int decoration, litehtml::font_metrics* fm )
+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 )
{
- litehtml::string_vector fonts;
- litehtml::split_string(faceName, fonts, ",");
- if (! fonts.empty()) {
- litehtml::trim(fonts[0]);
- }
-
- cairo_font_face_t* fnt = 0;
-
- FcPattern *pattern = FcPatternCreate();
- bool found = false;
- for(litehtml::string_vector::iterator i = fonts.begin(); i != fonts.end(); i++)
- {
- if(FcPatternAddString(pattern, FC_FAMILY, (unsigned char *) i->c_str()))
- {
- found = true;
- break;
- }
- }
- if(found)
- {
- if(italic == litehtml::fontStyleItalic )
- {
- FcPatternAddInteger (pattern, FC_SLANT, FC_SLANT_ITALIC);
- } else
- {
- FcPatternAddInteger (pattern, FC_SLANT, FC_SLANT_ROMAN);
- }
-
- int fc_weight = FC_WEIGHT_NORMAL;
- if(weight >= 0 && weight < 150) fc_weight = FC_WEIGHT_THIN;
- else if(weight >= 150 && weight < 250) fc_weight = FC_WEIGHT_EXTRALIGHT;
- else if(weight >= 250 && weight < 350) fc_weight = FC_WEIGHT_LIGHT;
- else if(weight >= 350 && weight < 450) fc_weight = FC_WEIGHT_NORMAL;
- else if(weight >= 450 && weight < 550) fc_weight = FC_WEIGHT_MEDIUM;
- else if(weight >= 550 && weight < 650) fc_weight = FC_WEIGHT_SEMIBOLD;
- else if(weight >= 650 && weight < 750) fc_weight = FC_WEIGHT_BOLD;
- else if(weight >= 750 && weight < 850) fc_weight = FC_WEIGHT_EXTRABOLD;
- else if(weight >= 950) fc_weight = FC_WEIGHT_BLACK;
-
- FcPatternAddInteger (pattern, FC_WEIGHT, fc_weight);
-
- fnt = cairo_ft_font_face_create_for_pattern(pattern);
- }
-
- FcPatternDestroy(pattern);
-
- cairo_font* ret = 0;
-
- if(fm && fnt)
+ 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;
- cairo_set_font_face(m_temp_cr, fnt);
- cairo_set_font_size(m_temp_cr, size);
- cairo_font_extents_t ext;
- cairo_font_extents(m_temp_cr, &ext);
+ pango_layout_set_text(layout, "x", 1);
- cairo_text_extents_t tex;
- cairo_text_extents(m_temp_cr, "x", &tex);
+ int x_width, x_height;
+ pango_layout_get_pixel_size(layout, &x_width, &x_height);
- fm->ascent = (int) ext.ascent;
- fm->descent = (int) ext.descent;
- fm->height = (int) (ext.ascent + ext.descent);
- fm->x_height = (int) tex.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 = fnt;
+ ret->font = desc;
ret->size = size;
- ret->strikeout = (decoration & litehtml::font_decoration_linethrough) ? true : false;
- ret->underline = (decoration & litehtml::font_decoration_underline) ? true : false;
-
+ 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 )
{
- cairo_font* fnt = (cairo_font*) hFont;
+ auto* fnt = (cairo_font*) hFont;
if(fnt)
{
- cairo_font_face_destroy(fnt->font);
+ pango_font_description_free(fnt->font);
delete fnt;
}
}
-int container_linux::text_width( const litehtml::tchar_t* text, litehtml::uint_ptr hFont )
+int container_linux::text_width( const char* text, litehtml::uint_ptr hFont )
{
- cairo_font* fnt = (cairo_font*) hFont;
+ auto* fnt = (cairo_font*) hFont;
cairo_save(m_temp_cr);
- if (fnt) {
- cairo_set_font_size(m_temp_cr, fnt->size);
- cairo_set_font_face(m_temp_cr, fnt->font);
- }
- cairo_text_extents_t ext;
- cairo_text_extents(m_temp_cr, text, &ext);
+ 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);
- return (int) ext.x_advance;
+ g_object_unref(layout);
+
+ return (int) x_width;
}
-void container_linux::draw_text( litehtml::uint_ptr hdc, const litehtml::tchar_t* text, litehtml::uint_ptr hFont, litehtml::web_color color, const litehtml::position& pos )
+void container_linux::draw_text( litehtml::uint_ptr hdc, const char* text, litehtml::uint_ptr hFont, litehtml::web_color color, const litehtml::position& pos )
{
- cairo_font* fnt = (cairo_font*) hFont;
- cairo_t* cr = (cairo_t*) hdc;
+ auto* fnt = (cairo_font*) hFont;
+ auto* cr = (cairo_t*) hdc;
cairo_save(cr);
apply_clip(cr);
- if (fnt) {
- cairo_set_font_face(cr, fnt->font);
- cairo_set_font_size(cr, fnt->size);
- }
- cairo_font_extents_t ext;
- cairo_font_extents(cr, &ext);
+ set_color(cr, color);
- int x = pos.left();
- int y = pos.bottom() - ext.descent;
+ PangoLayout *layout = pango_cairo_create_layout(cr);
+ pango_layout_set_font_description (layout, fnt->font);
+ pango_layout_set_text (layout, text, -1);
- set_color(cr, color);
+ 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);
- cairo_show_text(cr, text);
+ pango_cairo_update_layout (cr, layout);
+ pango_cairo_show_layout (cr, layout);
int tw = 0;
- if (fnt) {
- if(fnt->underline || fnt->strikeout)
- {
+ if(fnt->underline || fnt->strikeout)
+ {
tw = text_width(text, hFont);
- }
+ }
- if(fnt->underline)
- {
- cairo_set_line_width(cr, 1);
- cairo_move_to(cr, x, y + 1.5);
- cairo_line_to(cr, x + tw, y + 1.5);
+ 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_text_extents_t tex;
- cairo_text_extents(cr, "x", &tex);
-
- int ln_y = y - tex.height / 2.0;
-
- cairo_set_line_width(cr, 1);
- cairo_move_to(cr, x, (double) ln_y - 0.5);
- cairo_line_to(cr, x + tw, (double) ln_y - 0.5);
+ }
+ 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 )
+int container_linux::pt_to_px( int pt ) const
{
GdkScreen* screen = gdk_screen_get_default();
double dpi = gdk_screen_get_resolution(screen);
return (int) ((double) pt * dpi / 72.0);
}
+/*
int container_linux::get_default_font_size() const
{
- return 16;
+ 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();
{
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:
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);
}
}
-void container_linux::load_image( const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, bool redraw_on_ready )
+void container_linux::load_image( const char* src, const char* baseurl, bool redraw_on_ready )
{
- litehtml::tstring url;
+ litehtml::string url;
make_url(src, baseurl, url);
- bool found = false;
+ bool request = false;
+ struct timeval last;
- for (auto ii = m_images.cbegin(); ii != m_images.cend(); ++ii) {
- const image *i = &(*ii);
+ gettimeofday(&last, NULL);
- if (!strcmp(i->first.c_str(), url.c_str())) {
- found = true;
- break;
- }
- }
+ lock_images_cache();
- if(!found)
- {
- try
- {
- GdkPixbuf *img = get_image(url.c_str(), true);
- if(img)
- {
- m_images.push_back(std::make_pair(url, img));
+ 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;
}
- } catch(...)
- {
- int iii=0;
- iii++;
+
+ 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 litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, litehtml::size& sz )
+void container_linux::get_image_size( const char* src, const char* baseurl, litehtml::size& sz )
{
- litehtml::tstring url;
+ litehtml::string url;
make_url(src, baseurl, url);
- bool found = false;
- const image *img = NULL;
-
- for (auto ii = m_images.cbegin(); ii != m_images.cend(); ++ii) {
- const image *i = &(*ii);
- if (i->first == url) {
- img = i;
- found = true;
- break;
- }
- }
- if(img != NULL)
+ lock_images_cache();
+
+ auto img = m_images.find(url);
+ if(img != m_images.end())
{
- sz.width = gdk_pixbuf_get_width(img->second);
- sz.height = gdk_pixbuf_get_height(img->second);
+ 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;
+ sz.width = 0;
+ sz.height = 0;
}
+
+ unlock_images_cache();
}
-void container_linux::draw_background( litehtml::uint_ptr hdc, const litehtml::background_paint& bg )
+void container_linux::draw_background( litehtml::uint_ptr hdc, const std::vector<litehtml::background_paint>& 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);
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;
+ if(bg.image_size.height == 0 || bg.image_size.width == 0) continue;
- 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;
- }
- }
+ cairo_rectangle(cr, bg.clip_box.x, bg.clip_box.y, bg.clip_box.width, bg.clip_box.height);
+ cairo_clip(cr);
- if(img_i != NULL && img_i->second)
- {
- GdkPixbuf *bgbmp = img_i->second;
+ 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;
}
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);
{
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());
{
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);
{
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);
{
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());
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()
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);
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);
void container_linux::clear_images()
{
- for(auto i = m_images.begin(); i != m_images.end(); ++i) {
- image *img = &(*i);
+ lock_images_cache();
- if (img->second) {
- g_object_unref(img->second);
+ 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();
}
-void container_linux::clear_images(gint desired_size)
+gint container_linux::clear_images(gsize desired_size)
{
- gint size = 0;
+ gsize size = 0;
+ gint num = 0;
- /* First, tally up size of all the stored GdkPixbufs and
- * deallocate those which make the total size be above
- * the desired_size limit. We will remove their list
- * elements later. */
- for (auto i = m_images.rbegin(); i != m_images.rend(); ++i) {
- image *img = &(*i);
- gint cursize;
+ lock_images_cache();
- if (img->second == NULL)
+ /* 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_entry, decltype(lru_comp_func)> 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;
+ }
- cursize = gdk_pixbuf_get_byte_length(img->second);
+ 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) {
- g_object_unref(img->second);
- img->second = NULL;
+ 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;
}
}
- /* Remove elements whose GdkPixbuf pointers point to NULL. */
- m_images.remove_if([&](image _img) -> bool {
- if (_img.second == NULL)
- return true;
- return false;
- });
+ unlock_images_cache();
+
+ return num;
}
-const litehtml::tchar_t* container_linux::get_default_font_name() const
+/*
+const char* container_linux::get_default_font_name() const
{
return "Times New Roman";
}
+*/
-std::shared_ptr<litehtml::element> container_linux::create_element(const litehtml::tchar_t *tag_name,
+std::shared_ptr<litehtml::element> container_linux::create_element(const char *tag_name,
const litehtml::string_map &attributes,
const std::shared_ptr<litehtml::document> &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());
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);
}
}
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))
{
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<litehtml::document> &ptr, const litehtml::element::ptr& el)