Update current version of litehtml. Fix a crash when document contains no fonts
[claws.git] / src / plugins / litehtml_viewer / container_linux.cpp
1 /*
2  * Claws Mail -- A GTK+ based, lightweight, and fast e-mail client
3  * Copyright(C) 1999-2015 the Claws Mail Team
4  * == Fancy Plugin ==
5  * This file Copyright (C) 2009-2015 Salvatore De Paolis
6  * <iwkse@claws-mail.org> and the Claws Mail Team
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write tothe Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #include "claws-features.h"
23 #endif
24
25 #include "container_linux.h"
26
27 #include <cairo-ft.h>
28
29 #define _USE_MATH_DEFINES
30 #include <math.h>
31
32 #ifndef M_PI
33 #       define M_PI    3.14159265358979323846
34 #endif
35
36 container_linux::container_linux(void)
37 {
38         m_temp_surface  = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 2, 2);
39         m_temp_cr               = cairo_create(m_temp_surface);
40 }
41
42 container_linux::~container_linux(void)
43 {
44         clear_images();
45         cairo_surface_destroy(m_temp_surface);
46         cairo_destroy(m_temp_cr);
47 }
48
49 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 )
50 {
51         litehtml::string_vector fonts;
52         litehtml::split_string(faceName, fonts, ",");
53         if (! fonts.empty()) {
54             litehtml::trim(fonts[0]);
55         }
56
57         cairo_font_face_t* fnt = 0;
58
59         FcPattern *pattern = FcPatternCreate();
60         bool found = false;
61         for(litehtml::string_vector::iterator i = fonts.begin(); i != fonts.end(); i++)
62         {
63                 if(FcPatternAddString(pattern, FC_FAMILY, (unsigned char *) i->c_str()))
64                 {
65                         found = true;
66                         break;
67                 }
68         }
69         if(found)
70         {
71                 if(italic == litehtml::fontStyleItalic )
72                 {
73                         FcPatternAddInteger (pattern, FC_SLANT, FC_SLANT_ITALIC);
74                 } else
75                 {
76                         FcPatternAddInteger (pattern, FC_SLANT, FC_SLANT_ROMAN);
77                 }
78
79                 int fc_weight = FC_WEIGHT_NORMAL;
80                 if(weight >= 0 && weight < 150)                 fc_weight = FC_WEIGHT_THIN;
81                 else if(weight >= 150 && weight < 250)  fc_weight = FC_WEIGHT_EXTRALIGHT;
82                 else if(weight >= 250 && weight < 350)  fc_weight = FC_WEIGHT_LIGHT;
83                 else if(weight >= 350 && weight < 450)  fc_weight = FC_WEIGHT_NORMAL;
84                 else if(weight >= 450 && weight < 550)  fc_weight = FC_WEIGHT_MEDIUM;
85                 else if(weight >= 550 && weight < 650)  fc_weight = FC_WEIGHT_SEMIBOLD;
86                 else if(weight >= 650 && weight < 750)  fc_weight = FC_WEIGHT_BOLD;
87                 else if(weight >= 750 && weight < 850)  fc_weight = FC_WEIGHT_EXTRABOLD;
88                 else if(weight >= 950)                                  fc_weight = FC_WEIGHT_BLACK;
89
90                 FcPatternAddInteger (pattern, FC_WEIGHT, fc_weight);
91
92                 fnt = cairo_ft_font_face_create_for_pattern(pattern);
93         }
94
95         FcPatternDestroy(pattern);
96
97         cairo_font* ret = 0;
98
99         if(fm && fnt)
100         {
101                 cairo_save(m_temp_cr);
102
103                 cairo_set_font_face(m_temp_cr, fnt);
104                 cairo_set_font_size(m_temp_cr, size);
105                 cairo_font_extents_t ext;
106                 cairo_font_extents(m_temp_cr, &ext);
107
108                 cairo_text_extents_t tex;
109                 cairo_text_extents(m_temp_cr, "x", &tex);
110
111                 fm->ascent              = (int) ext.ascent;
112                 fm->descent             = (int) ext.descent;
113                 fm->height              = (int) (ext.ascent + ext.descent);
114                 fm->x_height    = (int) tex.height;
115
116                 cairo_restore(m_temp_cr);
117
118                 ret = new cairo_font;
119                 ret->font               = fnt;
120                 ret->size               = size;
121                 ret->strikeout  = (decoration & litehtml::font_decoration_linethrough) ? true : false;
122                 ret->underline  = (decoration & litehtml::font_decoration_underline) ? true : false;
123
124         }
125
126         return (litehtml::uint_ptr) ret;
127 }
128
129 void container_linux::delete_font( litehtml::uint_ptr hFont )
130 {
131         cairo_font* fnt = (cairo_font*) hFont;
132         if(fnt)
133         {
134                 cairo_font_face_destroy(fnt->font);
135                 delete fnt;
136         }
137 }
138
139 int container_linux::text_width( const litehtml::tchar_t* text, litehtml::uint_ptr hFont )
140 {
141         cairo_font* fnt = (cairo_font*) hFont;
142
143         cairo_save(m_temp_cr);
144
145         if (fnt) {
146             cairo_set_font_size(m_temp_cr, fnt->size);
147             cairo_set_font_face(m_temp_cr, fnt->font);
148         }
149         cairo_text_extents_t ext;
150         cairo_text_extents(m_temp_cr, text, &ext);
151
152         cairo_restore(m_temp_cr);
153
154         return (int) ext.x_advance;
155 }
156
157 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 )
158 {
159         cairo_font* fnt = (cairo_font*) hFont;
160         cairo_t* cr             = (cairo_t*) hdc;
161         cairo_save(cr);
162
163         apply_clip(cr);
164
165         if (fnt) {
166             cairo_set_font_face(cr, fnt->font);
167             cairo_set_font_size(cr, fnt->size);
168         }
169         cairo_font_extents_t ext;
170         cairo_font_extents(cr, &ext);
171
172         int x = pos.left();
173         int y = pos.bottom()    - ext.descent;
174
175         set_color(cr, color);
176
177         cairo_move_to(cr, x, y);
178         cairo_show_text(cr, text);
179
180         int tw = 0;
181
182         if (fnt) {
183             if(fnt->underline || fnt->strikeout)
184             {
185                 tw = text_width(text, hFont);
186             }
187
188             if(fnt->underline)
189             {
190                 cairo_set_line_width(cr, 1);
191                 cairo_move_to(cr, x, y + 1.5);
192                 cairo_line_to(cr, x + tw, y + 1.5);
193                 cairo_stroke(cr);
194             }
195             if(fnt->strikeout)
196             {
197                 cairo_text_extents_t tex;
198                 cairo_text_extents(cr, "x", &tex);
199
200                 int ln_y = y - tex.height / 2.0;
201
202                 cairo_set_line_width(cr, 1);
203                 cairo_move_to(cr, x, (double) ln_y - 0.5);
204                 cairo_line_to(cr, x + tw, (double) ln_y - 0.5);
205                 cairo_stroke(cr);
206             }
207         }   
208
209         cairo_restore(cr);
210 }
211
212 int container_linux::pt_to_px( int pt )
213 {
214         GdkScreen* screen = gdk_screen_get_default();
215         double dpi = gdk_screen_get_resolution(screen);
216
217         return (int) ((double) pt * dpi / 72.0);
218 }
219
220 int container_linux::get_default_font_size() const
221 {
222         return 16;
223 }
224
225 void container_linux::draw_list_marker( litehtml::uint_ptr hdc, const litehtml::list_marker& marker )
226 {
227         if(!marker.image.empty())
228         {
229                 /*litehtml::tstring url;
230                 make_url(marker.image.c_str(), marker.baseurl, url);
231
232                 lock_images_cache();
233                 images_map::iterator img_i = m_images.find(url.c_str());
234                 if(img_i != m_images.end())
235                 {
236                         if(img_i->second)
237                         {
238                                 draw_txdib((cairo_t*) hdc, img_i->second, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height);
239                         }
240                 }
241                 unlock_images_cache();*/
242         } else
243         {
244                 switch(marker.marker_type)
245                 {
246                 case litehtml::list_style_type_circle:
247                         {
248                                 draw_ellipse((cairo_t*) hdc, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height, marker.color, 0.5);
249                         }
250                         break;
251                 case litehtml::list_style_type_disc:
252                         {
253                                 fill_ellipse((cairo_t*) hdc, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height, marker.color);
254                         }
255                         break;
256                 case litehtml::list_style_type_square:
257                         if(hdc)
258                         {
259                                 cairo_t* cr = (cairo_t*) hdc;
260                                 cairo_save(cr);
261
262                                 cairo_new_path(cr);
263                                 cairo_rectangle(cr, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height);
264
265                                 set_color(cr, marker.color);
266                                 cairo_fill(cr);
267                                 cairo_restore(cr);
268                         }
269                         break;
270                 default:
271                         /*do nothing*/
272                         break;
273                 }
274         }
275 }
276
277 void container_linux::load_image( const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, bool redraw_on_ready )
278 {
279         litehtml::tstring url;
280         make_url(src, baseurl, url);
281         if(m_images.find(url.c_str()) == m_images.end())
282         {
283                 try
284                 {
285                         GdkPixbuf *img = get_image(url.c_str(), true);
286                         if(img)
287                         {
288                                 m_images[url.c_str()] = img;
289                         }
290                 } catch(...)
291                 {
292                         int iii=0;
293                         iii++;
294                 }
295         }
296 }
297
298 void container_linux::get_image_size( const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, litehtml::size& sz )
299 {
300         litehtml::tstring url;
301         make_url(src, baseurl, url);
302
303         images_map::iterator img = m_images.find(url.c_str());
304         if(img != m_images.end())
305         {
306                 sz.width        = gdk_pixbuf_get_width(img->second);
307                 sz.height       = gdk_pixbuf_get_height(img->second);
308         } else
309         {
310                 sz.width        = 0;
311                 sz.height       = 0;
312         }
313 }
314
315 void container_linux::draw_background( litehtml::uint_ptr hdc, const litehtml::background_paint& bg )
316 {
317         cairo_t* cr = (cairo_t*) hdc;
318         cairo_save(cr);
319         apply_clip(cr);
320
321         rounded_rectangle(cr, bg.border_box, bg.border_radius);
322         cairo_clip(cr);
323
324         cairo_rectangle(cr, bg.clip_box.x, bg.clip_box.y, bg.clip_box.width, bg.clip_box.height);
325         cairo_clip(cr);
326
327         if(bg.color.alpha)
328         {
329                 set_color(cr, bg.color);
330                 cairo_paint(cr);
331         }
332
333         litehtml::tstring url;
334         make_url(bg.image.c_str(), bg.baseurl.c_str(), url);
335
336         //lock_images_cache();
337         images_map::iterator img_i = m_images.find(url.c_str());
338         if(img_i != m_images.end() && img_i->second)
339         {
340                 GdkPixbuf *bgbmp = img_i->second;
341
342                 GdkPixbuf *new_img;
343                 if(bg.image_size.width != gdk_pixbuf_get_width(bgbmp) || bg.image_size.height != gdk_pixbuf_get_height(bgbmp))
344                 {
345                         new_img = gdk_pixbuf_scale_simple(bgbmp, bg.image_size.width, bg.image_size.height, GDK_INTERP_BILINEAR);
346                         bgbmp = new_img;
347                 }
348
349                 cairo_surface_t* img = surface_from_pixbuf(bgbmp);
350                 cairo_pattern_t *pattern = cairo_pattern_create_for_surface(img);
351                 cairo_matrix_t flib_m;
352                 cairo_matrix_init_identity(&flib_m);
353                 cairo_matrix_translate(&flib_m, -bg.position_x, -bg.position_y);
354                 cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
355                 cairo_pattern_set_matrix (pattern, &flib_m);
356
357                 switch(bg.repeat)
358                 {
359                 case litehtml::background_repeat_no_repeat:
360                         draw_pixbuf(cr, bgbmp, bg.position_x, bg.position_y, gdk_pixbuf_get_width(bgbmp), gdk_pixbuf_get_height(bgbmp));
361                         break;
362
363                 case litehtml::background_repeat_repeat_x:
364                         cairo_set_source(cr, pattern);
365                         cairo_rectangle(cr, bg.clip_box.left(), bg.position_y, bg.clip_box.width, gdk_pixbuf_get_height(bgbmp));
366                         cairo_fill(cr);
367                         break;
368
369                 case litehtml::background_repeat_repeat_y:
370                         cairo_set_source(cr, pattern);
371                         cairo_rectangle(cr, bg.position_x, bg.clip_box.top(), gdk_pixbuf_get_width(bgbmp), bg.clip_box.height);
372                         cairo_fill(cr);
373                         break;
374
375                 case litehtml::background_repeat_repeat:
376                         cairo_set_source(cr, pattern);
377                         cairo_rectangle(cr, bg.clip_box.left(), bg.clip_box.top(), bg.clip_box.width, bg.clip_box.height);
378                         cairo_fill(cr);
379                         break;
380                 }
381
382                 cairo_pattern_destroy(pattern);
383                 cairo_surface_destroy(img);
384
385         }
386 //      unlock_images_cache();
387         cairo_restore(cr);
388 }
389
390 void container_linux::make_url(const litehtml::tchar_t* url,    const litehtml::tchar_t* basepath, litehtml::tstring& out)
391 {
392         out = url;
393 }
394
395 void container_linux::add_path_arc(cairo_t* cr, double x, double y, double rx, double ry, double a1, double a2, bool neg)
396 {
397         if(rx > 0 && ry > 0)
398         {
399
400                 cairo_save(cr);
401
402                 cairo_translate(cr, x, y);
403                 cairo_scale(cr, 1, ry / rx);
404                 cairo_translate(cr, -x, -y);
405
406                 if(neg)
407                 {
408                         cairo_arc_negative(cr, x, y, rx, a1, a2);
409                 } else
410                 {
411                         cairo_arc(cr, x, y, rx, a1, a2);
412                 }
413
414                 cairo_restore(cr);
415         } else
416         {
417                 cairo_move_to(cr, x, y);
418         }
419 }
420
421 void container_linux::draw_borders(litehtml::uint_ptr hdc, const litehtml::borders& borders, const litehtml::position& draw_pos, bool root)
422 {
423         cairo_t* cr = (cairo_t*) hdc;
424         cairo_save(cr);
425         apply_clip(cr);
426
427         cairo_new_path(cr);
428
429         int bdr_top             = 0;
430         int bdr_bottom  = 0;
431         int bdr_left    = 0;
432         int bdr_right   = 0;
433
434         if(borders.top.width != 0 && borders.top.style > litehtml::border_style_hidden)
435         {
436                 bdr_top = (int) borders.top.width;
437         }
438         if(borders.bottom.width != 0 && borders.bottom.style > litehtml::border_style_hidden)
439         {
440                 bdr_bottom = (int) borders.bottom.width;
441         }
442         if(borders.left.width != 0 && borders.left.style > litehtml::border_style_hidden)
443         {
444                 bdr_left = (int) borders.left.width;
445         }
446         if(borders.right.width != 0 && borders.right.style > litehtml::border_style_hidden)
447         {
448                 bdr_right = (int) borders.right.width;
449         }
450
451         // draw right border
452         if(bdr_right)
453         {
454                 set_color(cr, borders.right.color);
455
456                 double r_top    = borders.radius.top_right_x;
457                 double r_bottom = borders.radius.bottom_right_x;
458
459                 if(r_top)
460                 {
461                         double end_angle        = 2 * M_PI;
462                         double start_angle      = end_angle - M_PI / 2.0  / ((double) bdr_top / (double) bdr_right + 1);
463
464                         add_path_arc(cr,
465                                 draw_pos.right() - r_top,
466                                 draw_pos.top() + r_top,
467                                 r_top - bdr_right,
468                                 r_top - bdr_right + (bdr_right - bdr_top),
469                                 end_angle,
470                                 start_angle, true);
471
472                         add_path_arc(cr,
473                                 draw_pos.right() - r_top,
474                                 draw_pos.top() + r_top,
475                                 r_top,
476                                 r_top,
477                                 start_angle,
478                                 end_angle, false);
479                 } else
480                 {
481                         cairo_move_to(cr, draw_pos.right() - bdr_right, draw_pos.top() + bdr_top);
482                         cairo_line_to(cr, draw_pos.right(), draw_pos.top());
483                 }
484
485                 if(r_bottom)
486                 {
487                         cairo_line_to(cr, draw_pos.right(),     draw_pos.bottom() - r_bottom);
488
489                         double start_angle      = 0;
490                         double end_angle        = start_angle + M_PI / 2.0  / ((double) bdr_bottom / (double) bdr_right + 1);
491
492                         add_path_arc(cr,
493                                 draw_pos.right() - r_bottom,
494                                 draw_pos.bottom() - r_bottom,
495                                 r_bottom,
496                                 r_bottom,
497                                 start_angle,
498                                 end_angle, false);
499
500                         add_path_arc(cr,
501                                 draw_pos.right() - r_bottom,
502                                 draw_pos.bottom() - r_bottom,
503                                 r_bottom - bdr_right,
504                                 r_bottom - bdr_right + (bdr_right - bdr_bottom),
505                                 end_angle,
506                                 start_angle, true);
507                 } else
508                 {
509                         cairo_line_to(cr, draw_pos.right(),     draw_pos.bottom());
510                         cairo_line_to(cr, draw_pos.right() - bdr_right, draw_pos.bottom() - bdr_bottom);
511                 }
512
513                 cairo_fill(cr);
514         }
515
516         // draw bottom border
517         if(bdr_bottom)
518         {
519                 set_color(cr, borders.bottom.color);
520
521                 double r_left   = borders.radius.bottom_left_x;
522                 double r_right  = borders.radius.bottom_right_x;
523
524                 if(r_left)
525                 {
526                         double start_angle      = M_PI / 2.0;
527                         double end_angle        = start_angle + M_PI / 2.0  / ((double) bdr_left / (double) bdr_bottom + 1);
528
529                         add_path_arc(cr,
530                                 draw_pos.left() + r_left,
531                                 draw_pos.bottom() - r_left,
532                                 r_left - bdr_bottom + (bdr_bottom - bdr_left),
533                                 r_left - bdr_bottom,
534                                 start_angle,
535                                 end_angle, false);
536
537                         add_path_arc(cr,
538                                 draw_pos.left() + r_left,
539                                 draw_pos.bottom() - r_left,
540                                 r_left,
541                                 r_left,
542                                 end_angle,
543                                 start_angle, true);
544                 } else
545                 {
546                         cairo_move_to(cr, draw_pos.left(), draw_pos.bottom());
547                         cairo_line_to(cr, draw_pos.left() + bdr_left, draw_pos.bottom() - bdr_bottom);
548                 }
549
550                 if(r_right)
551                 {
552                         cairo_line_to(cr, draw_pos.right() - r_right,   draw_pos.bottom());
553
554                         double end_angle        = M_PI / 2.0;
555                         double start_angle      = end_angle - M_PI / 2.0  / ((double) bdr_right / (double) bdr_bottom + 1);
556
557                         add_path_arc(cr,
558                                 draw_pos.right() - r_right,
559                                 draw_pos.bottom() - r_right,
560                                 r_right,
561                                 r_right,
562                                 end_angle,
563                                 start_angle, true);
564
565                         add_path_arc(cr,
566                                 draw_pos.right() - r_right,
567                                 draw_pos.bottom() - r_right,
568                                 r_right - bdr_bottom + (bdr_bottom - bdr_right),
569                                 r_right - bdr_bottom,
570                                 start_angle,
571                                 end_angle, false);
572                 } else
573                 {
574                         cairo_line_to(cr, draw_pos.right() - bdr_right, draw_pos.bottom() - bdr_bottom);
575                         cairo_line_to(cr, draw_pos.right(),     draw_pos.bottom());
576                 }
577
578                 cairo_fill(cr);
579         }
580
581         // draw top border
582         if(bdr_top)
583         {
584                 set_color(cr, borders.top.color);
585
586                 double r_left   = borders.radius.top_left_x;
587                 double r_right  = borders.radius.top_right_x;
588
589                 if(r_left)
590                 {
591                         double end_angle        = M_PI * 3.0 / 2.0;
592                         double start_angle      = end_angle - M_PI / 2.0  / ((double) bdr_left / (double) bdr_top + 1);
593
594                         add_path_arc(cr,
595                                 draw_pos.left() + r_left,
596                                 draw_pos.top() + r_left,
597                                 r_left,
598                                 r_left,
599                                 end_angle,
600                                 start_angle, true);
601
602                         add_path_arc(cr,
603                                 draw_pos.left() + r_left,
604                                 draw_pos.top() + r_left,
605                                 r_left - bdr_top + (bdr_top - bdr_left),
606                                 r_left - bdr_top,
607                                 start_angle,
608                                 end_angle, false);
609                 } else
610                 {
611                         cairo_move_to(cr, draw_pos.left(), draw_pos.top());
612                         cairo_line_to(cr, draw_pos.left() + bdr_left, draw_pos.top() + bdr_top);
613                 }
614
615                 if(r_right)
616                 {
617                         cairo_line_to(cr, draw_pos.right() - r_right,   draw_pos.top() + bdr_top);
618
619                         double start_angle      = M_PI * 3.0 / 2.0;
620                         double end_angle        = start_angle + M_PI / 2.0  / ((double) bdr_right / (double) bdr_top + 1);
621
622                         add_path_arc(cr,
623                                 draw_pos.right() - r_right,
624                                 draw_pos.top() + r_right,
625                                 r_right - bdr_top + (bdr_top - bdr_right),
626                                 r_right - bdr_top,
627                                 start_angle,
628                                 end_angle, false);
629
630                         add_path_arc(cr,
631                                 draw_pos.right() - r_right,
632                                 draw_pos.top() + r_right,
633                                 r_right,
634                                 r_right,
635                                 end_angle,
636                                 start_angle, true);
637                 } else
638                 {
639                         cairo_line_to(cr, draw_pos.right() - bdr_right, draw_pos.top() + bdr_top);
640                         cairo_line_to(cr, draw_pos.right(),     draw_pos.top());
641                 }
642
643                 cairo_fill(cr);
644         }
645
646         // draw left border
647         if(bdr_left)
648         {
649                 set_color(cr, borders.left.color);
650
651                 double r_top    = borders.radius.top_left_x;
652                 double r_bottom = borders.radius.bottom_left_x;
653
654                 if(r_top)
655                 {
656                         double start_angle      = M_PI;
657                         double end_angle        = start_angle + M_PI / 2.0  / ((double) bdr_top / (double) bdr_left + 1);
658
659                         add_path_arc(cr,
660                                 draw_pos.left() + r_top,
661                                 draw_pos.top() + r_top,
662                                 r_top - bdr_left,
663                                 r_top - bdr_left + (bdr_left - bdr_top),
664                                 start_angle,
665                                 end_angle, false);
666
667                         add_path_arc(cr,
668                                 draw_pos.left() + r_top,
669                                 draw_pos.top() + r_top,
670                                 r_top,
671                                 r_top,
672                                 end_angle,
673                                 start_angle, true);
674                 } else
675                 {
676                         cairo_move_to(cr, draw_pos.left() + bdr_left, draw_pos.top() + bdr_top);
677                         cairo_line_to(cr, draw_pos.left(), draw_pos.top());
678                 }
679
680                 if(r_bottom)
681                 {
682                         cairo_line_to(cr, draw_pos.left(),      draw_pos.bottom() - r_bottom);
683
684                         double end_angle        = M_PI;
685                         double start_angle      = end_angle - M_PI / 2.0  / ((double) bdr_bottom / (double) bdr_left + 1);
686
687                         add_path_arc(cr,
688                                 draw_pos.left() + r_bottom,
689                                 draw_pos.bottom() - r_bottom,
690                                 r_bottom,
691                                 r_bottom,
692                                 end_angle,
693                                 start_angle, true);
694
695                         add_path_arc(cr,
696                                 draw_pos.left() + r_bottom,
697                                 draw_pos.bottom() - r_bottom,
698                                 r_bottom - bdr_left,
699                                 r_bottom - bdr_left + (bdr_left - bdr_bottom),
700                                 start_angle,
701                                 end_angle, false);
702                 } else
703                 {
704                         cairo_line_to(cr, draw_pos.left(),      draw_pos.bottom());
705                         cairo_line_to(cr, draw_pos.left() + bdr_left,   draw_pos.bottom() - bdr_bottom);
706                 }
707
708                 cairo_fill(cr);
709         }
710         cairo_restore(cr);
711 }
712
713 void container_linux::transform_text(litehtml::tstring& text, litehtml::text_transform tt)
714 {
715
716 }
717
718 void container_linux::set_clip( const litehtml::position& pos, const litehtml::border_radiuses& bdr_radius, bool valid_x, bool valid_y )
719 {
720         litehtml::position clip_pos = pos;
721         litehtml::position client_pos;
722         get_client_rect(client_pos);
723         if(!valid_x)
724         {
725                 clip_pos.x              = client_pos.x;
726                 clip_pos.width  = client_pos.width;
727         }
728         if(!valid_y)
729         {
730                 clip_pos.y              = client_pos.y;
731                 clip_pos.height = client_pos.height;
732         }
733         m_clips.emplace_back(clip_pos, bdr_radius);
734 }
735
736 void container_linux::del_clip()
737 {
738         if(!m_clips.empty())
739         {
740                 m_clips.pop_back();
741         }
742 }
743
744 void container_linux::apply_clip( cairo_t* cr )
745 {
746         for(const auto& clip_box : m_clips)
747         {
748                 rounded_rectangle(cr, clip_box.box, clip_box.radius);
749                 cairo_clip(cr);
750         }
751 }
752
753 void container_linux::draw_ellipse( cairo_t* cr, int x, int y, int width, int height, const litehtml::web_color& color, int line_width )
754 {
755         if(!cr) return;
756         cairo_save(cr);
757
758         apply_clip(cr);
759
760         cairo_new_path(cr);
761
762         cairo_translate (cr, x + width / 2.0, y + height / 2.0);
763         cairo_scale (cr, width / 2.0, height / 2.0);
764         cairo_arc (cr, 0, 0, 1, 0, 2 * M_PI);
765
766         set_color(cr, color);
767         cairo_set_line_width(cr, line_width);
768         cairo_stroke(cr);
769
770         cairo_restore(cr);
771 }
772
773 void container_linux::fill_ellipse( cairo_t* cr, int x, int y, int width, int height, const litehtml::web_color& color )
774 {
775         if(!cr) return;
776         cairo_save(cr);
777
778         apply_clip(cr);
779
780         cairo_new_path(cr);
781
782         cairo_translate (cr, x + width / 2.0, y + height / 2.0);
783         cairo_scale (cr, width / 2.0, height / 2.0);
784         cairo_arc (cr, 0, 0, 1, 0, 2 * M_PI);
785
786         set_color(cr, color);
787         cairo_fill(cr);
788
789         cairo_restore(cr);
790 }
791
792 void container_linux::clear_images()
793 {
794 /*      for(images_map::iterator i = m_images.begin(); i != m_images.end(); i++)
795         {
796                 if(i->second)
797                 {
798                         delete i->second;
799                 }
800         }
801         m_images.clear();
802 */
803 }
804
805 const litehtml::tchar_t* container_linux::get_default_font_name() const
806 {
807         return "Times New Roman";
808 }
809
810 std::shared_ptr<litehtml::element>      container_linux::create_element(const litehtml::tchar_t *tag_name,
811                                                                                                                                           const litehtml::string_map &attributes,
812                                                                                                                                           const std::shared_ptr<litehtml::document> &doc)
813 {
814         return 0;
815 }
816
817 void container_linux::rounded_rectangle( cairo_t* cr, const litehtml::position &pos, const litehtml::border_radiuses &radius )
818 {
819         cairo_new_path(cr);
820         if(radius.top_left_x)
821         {
822                 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);
823         } else
824         {
825                 cairo_move_to(cr, pos.left(), pos.top());
826         }
827
828         cairo_line_to(cr, pos.right() - radius.top_right_x, pos.top());
829
830         if(radius.top_right_x)
831         {
832                 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);
833         }
834
835         cairo_line_to(cr, pos.right(), pos.bottom() - radius.bottom_right_x);
836
837         if(radius.bottom_right_x)
838         {
839                 cairo_arc(cr, pos.right() - radius.bottom_right_x, pos.bottom() - radius.bottom_right_x, radius.bottom_right_x, 0, M_PI / 2.0);
840         }
841
842         cairo_line_to(cr, pos.left() - radius.bottom_left_x, pos.bottom());
843
844         if(radius.bottom_left_x)
845         {
846                 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);
847         }
848 }
849
850 void container_linux::draw_pixbuf(cairo_t* cr, const GdkPixbuf *bmp, int x,     int y, int cx, int cy)
851 {
852         cairo_save(cr);
853
854         {
855                 cairo_matrix_t flib_m;
856                 cairo_matrix_init(&flib_m, 1, 0, 0, -1, 0, 0);
857
858                 if(cx != gdk_pixbuf_get_width(bmp) || cy != gdk_pixbuf_get_height(bmp))
859                 {
860                         GdkPixbuf *new_img = gdk_pixbuf_scale_simple(bmp, cx, cy, GDK_INTERP_BILINEAR);
861                         gdk_cairo_set_source_pixbuf(cr, new_img, x, y);
862                         cairo_paint(cr);
863                 } else
864                 {
865                         gdk_cairo_set_source_pixbuf(cr, bmp, x, y);
866                         cairo_paint(cr);
867                 }
868         }
869
870         cairo_restore(cr);
871 }
872
873 cairo_surface_t* container_linux::surface_from_pixbuf(const GdkPixbuf *bmp)
874 {
875         cairo_surface_t* ret = NULL;
876
877         if(gdk_pixbuf_get_has_alpha(bmp))
878         {
879                 ret = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, gdk_pixbuf_get_width(bmp), gdk_pixbuf_get_height(bmp));
880         } else
881         {
882                 ret = cairo_image_surface_create(CAIRO_FORMAT_RGB24, gdk_pixbuf_get_width(bmp), gdk_pixbuf_get_height(bmp));
883         }
884
885 //      Cairo::RefPtr<Cairo::Surface> surface(new Cairo::Surface(ret, false));
886 //      Cairo::RefPtr<Cairo::Context> ctx = Cairo::Context::create(surface);
887 //      Gdk::Cairo::set_source_pixbuf(ctx, bmp, 0.0, 0.0);
888         cairo_t *ctx = cairo_create(ret);
889         cairo_paint(ctx);
890
891         return ret;
892 }
893
894 void container_linux::get_media_features(litehtml::media_features& media) const
895 {
896         litehtml::position client;
897     get_client_rect(client);
898         media.type                      = litehtml::media_type_screen;
899         media.width                     = client.width;
900         media.height            = client.height;
901         media.device_width      = gdk_screen_width();
902         media.device_height     = gdk_screen_height();
903         media.color                     = 8;
904         media.monochrome        = 0;
905         media.color_index       = 256;
906         media.resolution        = 96;
907 }
908
909 void container_linux::get_language(litehtml::tstring& language, litehtml::tstring& culture) const
910 {
911         language = _t("en");
912         culture = _t("");
913 }
914
915 void container_linux::link(const std::shared_ptr<litehtml::document> &ptr, const litehtml::element::ptr& el)
916 {
917
918 }