update copyright year
[claws.git] / src / plugins / litehtml_viewer / container_linux.cpp
index e4d3c1dad93092d393d578641b18650c803efcd3..19d226202e30d220df6a4c9b63158ac024987e05 100644 (file)
@@ -1,9 +1,7 @@
 /*
- * 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;
@@ -128,88 +124,92 @@ litehtml::uint_ptr container_linux::create_font( const litehtml::tchar_t* faceNa
 
 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);
@@ -217,16 +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 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();
@@ -245,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:
@@ -256,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);
@@ -274,71 +276,96 @@ void container_linux::draw_list_marker( litehtml::uint_ptr hdc, const litehtml::
        }
 }
 
-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);
 
@@ -351,75 +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;
+               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;
 }
@@ -452,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);
 
@@ -485,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());
@@ -550,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);
@@ -615,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);
@@ -680,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());
@@ -742,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()
@@ -784,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);
@@ -804,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);
@@ -823,68 +828,117 @@ void container_linux::fill_ellipse( cairo_t* cr, int x, int y, int width, int he
 
 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());
@@ -892,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);
        }
 }
 
@@ -937,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))
        {
@@ -972,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<litehtml::document> &ptr, const litehtml::element::ptr& el)