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