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