add support for Ayatana indicator to Notification plugin
[claws.git] / src / plugins / litehtml_viewer / container_linux.cpp
blob19d226202e30d220df6a4c9b63158ac024987e05
1 /*
2 * Claws Mail -- A GTK based, lightweight, and fast e-mail client
3 * Copyright(C) 2019 the Claws Mail Team
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.
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #include "claws-features.h"
21 #endif
23 #include "container_linux.h"
24 #include "container_linux_images.h"
26 #include <cmath>
27 #include "lh_prefs.h"
28 #include "utils.h"
30 #ifndef M_PI
31 # define M_PI 3.14159265358979323846
32 #endif
34 container_linux::container_linux()
36 m_temp_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 2, 2);
37 m_temp_cr = cairo_create(m_temp_surface);
38 g_rec_mutex_init(&m_images_lock);
41 container_linux::~container_linux()
43 clear_images();
44 cairo_surface_destroy(m_temp_surface);
45 cairo_destroy(m_temp_cr);
46 g_rec_mutex_clear(&m_images_lock);
49 litehtml::uint_ptr container_linux::create_font( const char* faceName, int size, int weight, litehtml::font_style italic, unsigned int decoration, litehtml::font_metrics* fm )
51 PangoFontDescription *desc = pango_font_description_from_string (faceName);
52 pango_font_description_set_absolute_size(desc, size * PANGO_SCALE);
53 if(italic == litehtml::font_style_italic)
55 pango_font_description_set_style(desc, PANGO_STYLE_ITALIC);
56 } else
58 pango_font_description_set_style(desc, PANGO_STYLE_NORMAL);
60 PangoWeight fnt_weight;
61 if(weight >= 0 && weight < 150) fnt_weight = PANGO_WEIGHT_THIN;
62 else if(weight >= 150 && weight < 250) fnt_weight = PANGO_WEIGHT_ULTRALIGHT;
63 else if(weight >= 250 && weight < 350) fnt_weight = PANGO_WEIGHT_LIGHT;
64 else if(weight >= 350 && weight < 450) fnt_weight = PANGO_WEIGHT_NORMAL;
65 else if(weight >= 450 && weight < 550) fnt_weight = PANGO_WEIGHT_MEDIUM;
66 else if(weight >= 550 && weight < 650) fnt_weight = PANGO_WEIGHT_SEMIBOLD;
67 else if(weight >= 650 && weight < 750) fnt_weight = PANGO_WEIGHT_BOLD;
68 else if(weight >= 750 && weight < 850) fnt_weight = PANGO_WEIGHT_ULTRABOLD;
69 else fnt_weight = PANGO_WEIGHT_HEAVY;
71 pango_font_description_set_weight(desc, fnt_weight);
73 cairo_font* ret = nullptr;
75 if(fm)
77 cairo_save(m_temp_cr);
78 PangoLayout *layout = pango_cairo_create_layout(m_temp_cr);
79 PangoContext *context = pango_layout_get_context(layout);
80 PangoLanguage *language = pango_language_get_default();
81 pango_layout_set_font_description(layout, desc);
82 PangoFontMetrics *metrics = pango_context_get_metrics(context, desc, language);
84 fm->ascent = PANGO_PIXELS((double)pango_font_metrics_get_ascent(metrics));
85 fm->descent = PANGO_PIXELS((double)pango_font_metrics_get_descent(metrics));
86 fm->height = fm->ascent + fm->descent;
87 fm->x_height = fm->height;
89 pango_layout_set_text(layout, "x", 1);
91 int x_width, x_height;
92 pango_layout_get_pixel_size(layout, &x_width, &x_height);
94 fm->x_height = x_height;
96 cairo_restore(m_temp_cr);
98 g_object_unref(layout);
99 pango_font_metrics_unref(metrics);
101 ret = new cairo_font;
102 ret->font = desc;
103 ret->size = size;
104 ret->strikeout = (decoration & litehtml::font_decoration_linethrough) != 0;
105 ret->underline = (decoration & litehtml::font_decoration_underline) != 0;
106 ret->ascent = fm->ascent;
107 ret->descent = fm->descent;
109 ret->underline_thickness = pango_font_metrics_get_underline_thickness(metrics);
110 ret->underline_position = -pango_font_metrics_get_underline_position(metrics);
111 pango_quantize_line_geometry(&ret->underline_thickness, &ret->underline_position);
112 ret->underline_thickness = PANGO_PIXELS(ret->underline_thickness);
113 ret->underline_position = -1;//PANGO_PIXELS(ret->underline_position);
115 ret->strikethrough_thickness = pango_font_metrics_get_strikethrough_thickness(metrics);
116 ret->strikethrough_position = pango_font_metrics_get_strikethrough_position(metrics);
117 pango_quantize_line_geometry(&ret->strikethrough_thickness, &ret->strikethrough_position);
118 ret->strikethrough_thickness = PANGO_PIXELS(ret->strikethrough_thickness);
119 ret->strikethrough_position = PANGO_PIXELS(ret->strikethrough_position);
122 return (litehtml::uint_ptr) ret;
125 void container_linux::delete_font( litehtml::uint_ptr hFont )
127 auto* fnt = (cairo_font*) hFont;
128 if(fnt)
130 pango_font_description_free(fnt->font);
131 delete fnt;
135 int container_linux::text_width( const char* text, litehtml::uint_ptr hFont )
137 auto* fnt = (cairo_font*) hFont;
139 cairo_save(m_temp_cr);
141 PangoLayout *layout = pango_cairo_create_layout(m_temp_cr);
142 pango_layout_set_font_description(layout, fnt->font);
144 pango_layout_set_text(layout, text, -1);
145 pango_cairo_update_layout (m_temp_cr, layout);
147 int x_width, x_height;
148 pango_layout_get_pixel_size(layout, &x_width, &x_height);
150 cairo_restore(m_temp_cr);
152 g_object_unref(layout);
154 return (int) x_width;
157 void container_linux::draw_text( litehtml::uint_ptr hdc, const char* text, litehtml::uint_ptr hFont, litehtml::web_color color, const litehtml::position& pos )
159 auto* fnt = (cairo_font*) hFont;
160 auto* cr = (cairo_t*) hdc;
161 cairo_save(cr);
163 apply_clip(cr);
165 set_color(cr, color);
167 PangoLayout *layout = pango_cairo_create_layout(cr);
168 pango_layout_set_font_description (layout, fnt->font);
169 pango_layout_set_text (layout, text, -1);
171 int baseline = PANGO_PIXELS(pango_layout_get_baseline(layout));
173 PangoRectangle ink_rect, logical_rect;
174 pango_layout_get_pixel_extents(layout, &ink_rect, &logical_rect);
176 int text_baseline = pos.height - fnt->descent;
178 int x = pos.left() + logical_rect.x;
179 int y = pos.top() + logical_rect.y + text_baseline - baseline;
181 cairo_move_to(cr, x, y);
182 pango_cairo_update_layout (cr, layout);
183 pango_cairo_show_layout (cr, layout);
185 int tw = 0;
187 if(fnt->underline || fnt->strikeout)
189 tw = text_width(text, hFont);
192 if(fnt->underline)
194 cairo_set_line_width(cr, fnt->underline_thickness);
195 cairo_move_to(cr, x, pos.top() + text_baseline - fnt->underline_position + 0.5);
196 cairo_line_to(cr, x + tw, pos.top() + text_baseline - fnt->underline_position + 0.5);
197 cairo_stroke(cr);
199 if(fnt->strikeout)
201 cairo_set_line_width(cr, fnt->strikethrough_thickness);
202 cairo_move_to(cr, x, pos.top() + text_baseline - fnt->strikethrough_position - 0.5);
203 cairo_line_to(cr, x + tw, pos.top() + text_baseline - fnt->strikethrough_position - 0.5);
204 cairo_stroke(cr);
207 cairo_restore(cr);
209 g_object_unref(layout);
212 int container_linux::pt_to_px( int pt ) const
214 GdkScreen* screen = gdk_screen_get_default();
215 double dpi = gdk_screen_get_resolution(screen);
217 return (int) ((double) pt * dpi / 72.0);
221 int container_linux::get_default_font_size() const
223 return pt_to_px(12);
227 void container_linux::draw_list_marker( litehtml::uint_ptr hdc, const litehtml::list_marker& marker )
229 if(!marker.image.empty())
231 /*litehtml::string url;
232 make_url(marker.image.c_str(), marker.baseurl, url);
234 lock_images_cache();
235 images_map::iterator img_i = m_images.find(url.c_str());
236 if(img_i != m_images.end())
238 if(img_i->second)
240 draw_txdib((cairo_t*) hdc, img_i->second, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height);
243 unlock_images_cache();*/
244 } else
246 switch(marker.marker_type)
248 case litehtml::list_style_type_circle:
250 draw_ellipse((cairo_t*) hdc, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height, marker.color, 1);
252 break;
253 case litehtml::list_style_type_disc:
255 fill_ellipse((cairo_t*) hdc, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height, marker.color);
257 break;
258 case litehtml::list_style_type_square:
259 if(hdc)
261 auto* cr = (cairo_t*) hdc;
262 cairo_save(cr);
264 cairo_new_path(cr);
265 cairo_rectangle(cr, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height);
267 set_color(cr, marker.color);
268 cairo_fill(cr);
269 cairo_restore(cr);
271 break;
272 default:
273 /*do nothing*/
274 break;
279 void container_linux::load_image( const char* src, const char* baseurl, bool redraw_on_ready )
281 litehtml::string url;
282 make_url(src, baseurl, url);
283 bool request = false;
284 struct timeval last;
286 gettimeofday(&last, NULL);
288 lock_images_cache();
290 auto i = m_images.find(url);
291 if(i == m_images.end()) {
292 /* Attached images can be loaded into cache right here. */
293 if (!strncmp(src, "cid:", 4)) {
294 GdkPixbuf *pixbuf = get_local_image(src);
296 if (pixbuf != NULL)
297 m_images.insert(std::make_pair(src, std::make_pair(pixbuf, last)));
299 unlock_images_cache();
300 return;
301 } else {
302 if (!lh_prefs_get()->enable_remote_content) {
303 debug_print("blocking download of image from '%s'\n", src);
304 unlock_images_cache();
305 return;
308 request = true;
309 m_images.insert(std::make_pair(url, std::make_pair((GdkPixbuf *)NULL, last)));
311 } else {
312 debug_print("found image cache entry: %p '%s'\n", i->second.first, url.c_str());
313 i->second.second = last;
316 unlock_images_cache();
318 if (request) {
319 struct FetchCtx *ctx;
321 debug_print("allowing download of image from '%s'\n", src);
323 ctx = g_new(struct FetchCtx, 1);
324 ctx->url = g_strdup(url.c_str());
325 ctx->container = this;
327 GTask *task = g_task_new(NULL, NULL, get_image_callback, ctx);
328 g_task_set_task_data(task, ctx, NULL);
329 g_task_run_in_thread(task, get_image_threaded);
333 void container_linux::get_image_size( const char* src, const char* baseurl, litehtml::size& sz )
335 litehtml::string url;
336 make_url(src, baseurl, url);
338 lock_images_cache();
340 auto img = m_images.find(url);
341 if(img != m_images.end())
343 if(img->second.first)
345 sz.width = gdk_pixbuf_get_width(img->second.first);
346 sz.height = gdk_pixbuf_get_height(img->second.first);
347 } else
349 sz.width = 0;
350 sz.height = 0;
352 } else
354 sz.width = 0;
355 sz.height = 0;
358 unlock_images_cache();
361 void container_linux::draw_background( litehtml::uint_ptr hdc, const std::vector<litehtml::background_paint>& bgvec )
363 auto* cr = (cairo_t*) hdc;
364 cairo_save(cr);
365 apply_clip(cr);
367 const auto& bg = bgvec.back();
369 rounded_rectangle(cr, bg.border_box, bg.border_radius);
370 cairo_clip(cr);
372 cairo_rectangle(cr, bg.clip_box.x, bg.clip_box.y, bg.clip_box.width, bg.clip_box.height);
373 cairo_clip(cr);
375 if(bg.color.alpha)
377 set_color(cr, bg.color);
378 cairo_paint(cr);
381 for (int i = (int)bgvec.size() - 1; i >= 0; i--)
383 const auto& bg = bgvec[i];
385 if(bg.image_size.height == 0 || bg.image_size.width == 0) continue;
387 cairo_rectangle(cr, bg.clip_box.x, bg.clip_box.y, bg.clip_box.width, bg.clip_box.height);
388 cairo_clip(cr);
390 std::string url;
391 make_url(bg.image.c_str(), bg.baseurl.c_str(), url);
393 lock_images_cache();
394 auto img_i = m_images.find(url);
395 if(img_i != m_images.end() && img_i->second.first)
397 GdkPixbuf *bgbmp = img_i->second.first;
399 GdkPixbuf *new_img = NULL;
400 if(bg.image_size.width != gdk_pixbuf_get_width(bgbmp) || bg.image_size.height != gdk_pixbuf_get_height(bgbmp))
402 new_img = gdk_pixbuf_scale_simple(bgbmp, bg.image_size.width, bg.image_size.height, GDK_INTERP_BILINEAR);
403 bgbmp = new_img;
406 cairo_surface_t* img = surface_from_pixbuf(bgbmp);
407 cairo_pattern_t *pattern = cairo_pattern_create_for_surface(img);
408 cairo_matrix_t flib_m;
409 cairo_matrix_init_identity(&flib_m);
410 cairo_matrix_translate(&flib_m, -bg.position_x, -bg.position_y);
411 cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
412 cairo_pattern_set_matrix (pattern, &flib_m);
414 switch(bg.repeat)
416 case litehtml::background_repeat_no_repeat:
417 draw_pixbuf(cr, bgbmp, bg.position_x, bg.position_y, gdk_pixbuf_get_width(bgbmp), gdk_pixbuf_get_height(bgbmp));
418 break;
420 case litehtml::background_repeat_repeat_x:
421 cairo_set_source(cr, pattern);
422 cairo_rectangle(cr, bg.clip_box.left(), bg.position_y, bg.clip_box.width, gdk_pixbuf_get_height(bgbmp));
423 cairo_fill(cr);
424 break;
426 case litehtml::background_repeat_repeat_y:
427 cairo_set_source(cr, pattern);
428 cairo_rectangle(cr, bg.position_x, bg.clip_box.top(), gdk_pixbuf_get_width(bgbmp), bg.clip_box.height);
429 cairo_fill(cr);
430 break;
432 case litehtml::background_repeat_repeat:
433 cairo_set_source(cr, pattern);
434 cairo_rectangle(cr, bg.clip_box.left(), bg.clip_box.top(), bg.clip_box.width, bg.clip_box.height);
435 cairo_fill(cr);
436 break;
439 cairo_pattern_destroy(pattern);
440 cairo_surface_destroy(img);
441 if(new_img)
443 g_object_unref(new_img);
446 unlock_images_cache();
449 cairo_restore(cr);
452 void container_linux::make_url(const char* url, const char* basepath, litehtml::string& out)
454 out = url;
457 void container_linux::add_path_arc(cairo_t* cr, double x, double y, double rx, double ry, double a1, double a2, bool neg)
459 if(rx > 0 && ry > 0)
462 cairo_save(cr);
464 cairo_translate(cr, x, y);
465 cairo_scale(cr, 1, ry / rx);
466 cairo_translate(cr, -x, -y);
468 if(neg)
470 cairo_arc_negative(cr, x, y, rx, a1, a2);
471 } else
473 cairo_arc(cr, x, y, rx, a1, a2);
476 cairo_restore(cr);
477 } else
479 cairo_move_to(cr, x, y);
483 void container_linux::draw_borders(litehtml::uint_ptr hdc, const litehtml::borders& borders, const litehtml::position& draw_pos, bool root)
485 auto* cr = (cairo_t*) hdc;
486 cairo_save(cr);
487 apply_clip(cr);
489 cairo_new_path(cr);
491 int bdr_top = 0;
492 int bdr_bottom = 0;
493 int bdr_left = 0;
494 int bdr_right = 0;
496 if(borders.top.width != 0 && borders.top.style > litehtml::border_style_hidden)
498 bdr_top = (int) borders.top.width;
500 if(borders.bottom.width != 0 && borders.bottom.style > litehtml::border_style_hidden)
502 bdr_bottom = (int) borders.bottom.width;
504 if(borders.left.width != 0 && borders.left.style > litehtml::border_style_hidden)
506 bdr_left = (int) borders.left.width;
508 if(borders.right.width != 0 && borders.right.style > litehtml::border_style_hidden)
510 bdr_right = (int) borders.right.width;
513 // draw right border
514 if(bdr_right)
516 set_color(cr, borders.right.color);
518 if(borders.radius.top_right_x && borders.radius.top_right_y)
520 double end_angle = 2 * M_PI;
521 double start_angle = end_angle - M_PI / 2.0 / ((double) bdr_top / (double) bdr_right + 1);
523 add_path_arc(cr,
524 draw_pos.right() - borders.radius.top_right_x,
525 draw_pos.top() + borders.radius.top_right_y,
526 borders.radius.top_right_x - bdr_right,
527 borders.radius.top_right_y - bdr_right + (bdr_right - bdr_top),
528 end_angle,
529 start_angle, true);
531 add_path_arc(cr,
532 draw_pos.right() - borders.radius.top_right_x,
533 draw_pos.top() + borders.radius.top_right_y,
534 borders.radius.top_right_x,
535 borders.radius.top_right_y,
536 start_angle,
537 end_angle, false);
538 } else
540 cairo_move_to(cr, draw_pos.right() - bdr_right, draw_pos.top() + bdr_top);
541 cairo_line_to(cr, draw_pos.right(), draw_pos.top());
544 if(borders.radius.bottom_right_x && borders.radius.bottom_right_y)
546 cairo_line_to(cr, draw_pos.right(), draw_pos.bottom() - borders.radius.bottom_right_y);
548 double start_angle = 0;
549 double end_angle = start_angle + M_PI / 2.0 / ((double) bdr_bottom / (double) bdr_right + 1);
551 add_path_arc(cr,
552 draw_pos.right() - borders.radius.bottom_right_x,
553 draw_pos.bottom() - borders.radius.bottom_right_y,
554 borders.radius.bottom_right_x,
555 borders.radius.bottom_right_y,
556 start_angle,
557 end_angle, false);
559 add_path_arc(cr,
560 draw_pos.right() - borders.radius.bottom_right_x,
561 draw_pos.bottom() - borders.radius.bottom_right_y,
562 borders.radius.bottom_right_x - bdr_right,
563 borders.radius.bottom_right_y - bdr_right + (bdr_right - bdr_bottom),
564 end_angle,
565 start_angle, true);
566 } else
568 cairo_line_to(cr, draw_pos.right(), draw_pos.bottom());
569 cairo_line_to(cr, draw_pos.right() - bdr_right, draw_pos.bottom() - bdr_bottom);
572 cairo_fill(cr);
575 // draw bottom border
576 if(bdr_bottom)
578 set_color(cr, borders.bottom.color);
580 if(borders.radius.bottom_left_x && borders.radius.bottom_left_y)
582 double start_angle = M_PI / 2.0;
583 double end_angle = start_angle + M_PI / 2.0 / ((double) bdr_left / (double) bdr_bottom + 1);
585 add_path_arc(cr,
586 draw_pos.left() + borders.radius.bottom_left_x,
587 draw_pos.bottom() - borders.radius.bottom_left_y,
588 borders.radius.bottom_left_x - bdr_bottom + (bdr_bottom - bdr_left),
589 borders.radius.bottom_left_y - bdr_bottom,
590 start_angle,
591 end_angle, false);
593 add_path_arc(cr,
594 draw_pos.left() + borders.radius.bottom_left_x,
595 draw_pos.bottom() - borders.radius.bottom_left_y,
596 borders.radius.bottom_left_x,
597 borders.radius.bottom_left_y,
598 end_angle,
599 start_angle, true);
600 } else
602 cairo_move_to(cr, draw_pos.left(), draw_pos.bottom());
603 cairo_line_to(cr, draw_pos.left() + bdr_left, draw_pos.bottom() - bdr_bottom);
606 if(borders.radius.bottom_right_x && borders.radius.bottom_right_y)
608 cairo_line_to(cr, draw_pos.right() - borders.radius.bottom_right_x, draw_pos.bottom());
610 double end_angle = M_PI / 2.0;
611 double start_angle = end_angle - M_PI / 2.0 / ((double) bdr_right / (double) bdr_bottom + 1);
613 add_path_arc(cr,
614 draw_pos.right() - borders.radius.bottom_right_x,
615 draw_pos.bottom() - borders.radius.bottom_right_y,
616 borders.radius.bottom_right_x,
617 borders.radius.bottom_right_y,
618 end_angle,
619 start_angle, true);
621 add_path_arc(cr,
622 draw_pos.right() - borders.radius.bottom_right_x,
623 draw_pos.bottom() - borders.radius.bottom_right_y,
624 borders.radius.bottom_right_x - bdr_bottom + (bdr_bottom - bdr_right),
625 borders.radius.bottom_right_y - bdr_bottom,
626 start_angle,
627 end_angle, false);
628 } else
630 cairo_line_to(cr, draw_pos.right() - bdr_right, draw_pos.bottom() - bdr_bottom);
631 cairo_line_to(cr, draw_pos.right(), draw_pos.bottom());
634 cairo_fill(cr);
637 // draw top border
638 if(bdr_top)
640 set_color(cr, borders.top.color);
642 if(borders.radius.top_left_x && borders.radius.top_left_y)
644 double end_angle = M_PI * 3.0 / 2.0;
645 double start_angle = end_angle - M_PI / 2.0 / ((double) bdr_left / (double) bdr_top + 1);
647 add_path_arc(cr,
648 draw_pos.left() + borders.radius.top_left_x,
649 draw_pos.top() + borders.radius.top_left_y,
650 borders.radius.top_left_x,
651 borders.radius.top_left_y,
652 end_angle,
653 start_angle, true);
655 add_path_arc(cr,
656 draw_pos.left() + borders.radius.top_left_x,
657 draw_pos.top() + borders.radius.top_left_y,
658 borders.radius.top_left_x - bdr_top + (bdr_top - bdr_left),
659 borders.radius.top_left_y - bdr_top,
660 start_angle,
661 end_angle, false);
662 } else
664 cairo_move_to(cr, draw_pos.left(), draw_pos.top());
665 cairo_line_to(cr, draw_pos.left() + bdr_left, draw_pos.top() + bdr_top);
668 if(borders.radius.top_right_x && borders.radius.top_right_y)
670 cairo_line_to(cr, draw_pos.right() - borders.radius.top_right_x, draw_pos.top() + bdr_top);
672 double start_angle = M_PI * 3.0 / 2.0;
673 double end_angle = start_angle + M_PI / 2.0 / ((double) bdr_right / (double) bdr_top + 1);
675 add_path_arc(cr,
676 draw_pos.right() - borders.radius.top_right_x,
677 draw_pos.top() + borders.radius.top_right_y,
678 borders.radius.top_right_x - bdr_top + (bdr_top - bdr_right),
679 borders.radius.top_right_y - bdr_top,
680 start_angle,
681 end_angle, false);
683 add_path_arc(cr,
684 draw_pos.right() - borders.radius.top_right_x,
685 draw_pos.top() + borders.radius.top_right_y,
686 borders.radius.top_right_x,
687 borders.radius.top_right_y,
688 end_angle,
689 start_angle, true);
690 } else
692 cairo_line_to(cr, draw_pos.right() - bdr_right, draw_pos.top() + bdr_top);
693 cairo_line_to(cr, draw_pos.right(), draw_pos.top());
696 cairo_fill(cr);
699 // draw left border
700 if(bdr_left)
702 set_color(cr, borders.left.color);
704 if(borders.radius.top_left_x && borders.radius.top_left_y)
706 double start_angle = M_PI;
707 double end_angle = start_angle + M_PI / 2.0 / ((double) bdr_top / (double) bdr_left + 1);
709 add_path_arc(cr,
710 draw_pos.left() + borders.radius.top_left_x,
711 draw_pos.top() + borders.radius.top_left_y,
712 borders.radius.top_left_x - bdr_left,
713 borders.radius.top_left_y - bdr_left + (bdr_left - bdr_top),
714 start_angle,
715 end_angle, false);
717 add_path_arc(cr,
718 draw_pos.left() + borders.radius.top_left_x,
719 draw_pos.top() + borders.radius.top_left_y,
720 borders.radius.top_left_x,
721 borders.radius.top_left_y,
722 end_angle,
723 start_angle, true);
724 } else
726 cairo_move_to(cr, draw_pos.left() + bdr_left, draw_pos.top() + bdr_top);
727 cairo_line_to(cr, draw_pos.left(), draw_pos.top());
730 if(borders.radius.bottom_left_x && borders.radius.bottom_left_y)
732 cairo_line_to(cr, draw_pos.left(), draw_pos.bottom() - borders.radius.bottom_left_y);
734 double end_angle = M_PI;
735 double start_angle = end_angle - M_PI / 2.0 / ((double) bdr_bottom / (double) bdr_left + 1);
737 add_path_arc(cr,
738 draw_pos.left() + borders.radius.bottom_left_x,
739 draw_pos.bottom() - borders.radius.bottom_left_y,
740 borders.radius.bottom_left_x,
741 borders.radius.bottom_left_y,
742 end_angle,
743 start_angle, true);
745 add_path_arc(cr,
746 draw_pos.left() + borders.radius.bottom_left_x,
747 draw_pos.bottom() - borders.radius.bottom_left_y,
748 borders.radius.bottom_left_x - bdr_left,
749 borders.radius.bottom_left_y - bdr_left + (bdr_left - bdr_bottom),
750 start_angle,
751 end_angle, false);
752 } else
754 cairo_line_to(cr, draw_pos.left(), draw_pos.bottom());
755 cairo_line_to(cr, draw_pos.left() + bdr_left, draw_pos.bottom() - bdr_bottom);
758 cairo_fill(cr);
760 cairo_restore(cr);
763 void container_linux::transform_text(litehtml::string& text, litehtml::text_transform tt)
768 void container_linux::set_clip( const litehtml::position& pos, const litehtml::border_radiuses& bdr_radius )
770 m_clips.emplace_back(pos, bdr_radius);
773 void container_linux::del_clip()
775 if(!m_clips.empty())
777 m_clips.pop_back();
781 void container_linux::apply_clip( cairo_t* cr )
783 for(const auto& clip_box : m_clips)
785 rounded_rectangle(cr, clip_box.box, clip_box.radius);
786 cairo_clip(cr);
790 void container_linux::draw_ellipse( cairo_t* cr, int x, int y, int width, int height, const litehtml::web_color& color, int line_width )
792 if(!cr || !width || !height) return;
793 cairo_save(cr);
795 apply_clip(cr);
797 cairo_new_path(cr);
799 cairo_translate (cr, x + width / 2.0, y + height / 2.0);
800 cairo_scale (cr, width / 2.0, height / 2.0);
801 cairo_arc (cr, 0, 0, 1, 0, 2 * M_PI);
803 set_color(cr, color);
804 cairo_set_line_width(cr, line_width);
805 cairo_stroke(cr);
807 cairo_restore(cr);
810 void container_linux::fill_ellipse( cairo_t* cr, int x, int y, int width, int height, const litehtml::web_color& color )
812 if(!cr || !width || !height) return;
813 cairo_save(cr);
815 apply_clip(cr);
817 cairo_new_path(cr);
819 cairo_translate (cr, x + width / 2.0, y + height / 2.0);
820 cairo_scale (cr, width / 2.0, height / 2.0);
821 cairo_arc (cr, 0, 0, 1, 0, 2 * M_PI);
823 set_color(cr, color);
824 cairo_fill(cr);
826 cairo_restore(cr);
829 void container_linux::clear_images()
831 lock_images_cache();
833 for(auto i = m_images.begin(); i != m_images.end(); ++i) {
834 if (i->second.first) {
835 g_object_unref(i->second.first);
839 m_images.clear();
841 unlock_images_cache();
844 gint container_linux::clear_images(gsize desired_size)
846 gsize size = 0;
847 gint num = 0;
849 lock_images_cache();
851 /* First, remove all local images - the ones with "cid:" URL. */
852 for (auto i = m_images.begin(); i != m_images.end(); ) {
853 if (!strncmp(i->first.c_str(), "cid:", 4)) {
854 g_object_unref(i->second.first);
855 i = m_images.erase(i);
856 num++;
857 } else {
858 ++i;
862 /* Second, build an LRU list */
863 auto lru_comp_func = [](const lru_entry& l1, const lru_entry& l2) {
864 return timercmp(&l1.second, &l2.second, <);
866 std::set<lru_entry, decltype(lru_comp_func)> lru(lru_comp_func);
868 for (auto i = m_images.begin(); i != m_images.end(); ++i) {
869 lru.insert(std::make_pair(i->first, i->second.second));
873 for (auto l = lru.begin(); l != lru.end(); l++) {
874 debug_print("lru dump: %d %d %s\n", l->second.tv_sec, l->second.tv_usec, l->first.c_str());
878 /* Last, walk the LRU list and remove the oldest entries that push it over
879 * the desired size limit */
880 for (auto l = lru.rbegin(); l != lru.rend(); ++l) {
881 gsize cursize;
883 auto i = m_images.find(l->first);
885 if(i == m_images.end()) {
886 g_warning("failed to find '%s' in m_images", l->first.c_str());
887 continue;
890 if(i->second.first == NULL) {
891 /* This should mean that the download is still in progress */
892 debug_print("warning - trying to prune a null pixbuf for %s\n", i->first.c_str());
893 continue;
896 cursize = gdk_pixbuf_get_byte_length(i->second.first);
898 debug_print("clear_images: desired_size %d - size %d - cursize %d - %d %d %s\n",
899 desired_size, size, cursize, l->second.tv_sec, l->second.tv_usec, l->first.c_str());
901 if (size + cursize > desired_size) {
902 debug_print("pruning %s from image cache\n", i->first.c_str());
903 g_object_unref(i->second.first);
904 m_images.erase(i);
905 num++;
906 } else {
907 size += cursize;
911 unlock_images_cache();
913 return num;
917 const char* container_linux::get_default_font_name() const
919 return "Times New Roman";
923 std::shared_ptr<litehtml::element> container_linux::create_element(const char *tag_name,
924 const litehtml::string_map &attributes,
925 const std::shared_ptr<litehtml::document> &doc)
927 return nullptr;
930 void container_linux::rounded_rectangle( cairo_t* cr, const litehtml::position &pos, const litehtml::border_radiuses &radius )
932 cairo_new_path(cr);
933 if(radius.top_left_x && radius.top_left_y)
935 add_path_arc(cr,
936 pos.left() + radius.top_left_x,
937 pos.top() + radius.top_left_y,
938 radius.top_left_x,
939 radius.top_left_y,
940 M_PI,
941 M_PI * 3.0 / 2.0, false);
942 } else
944 cairo_move_to(cr, pos.left(), pos.top());
947 cairo_line_to(cr, pos.right() - radius.top_right_x, pos.top());
949 if(radius.top_right_x && radius.top_right_y)
951 add_path_arc(cr,
952 pos.right() - radius.top_right_x,
953 pos.top() + radius.top_right_y,
954 radius.top_right_x,
955 radius.top_right_y,
956 M_PI * 3.0 / 2.0,
957 2.0 * M_PI, false);
960 cairo_line_to(cr, pos.right(), pos.bottom() - radius.bottom_right_x);
962 if(radius.bottom_right_x && radius.bottom_right_y)
964 add_path_arc(cr,
965 pos.right() - radius.bottom_right_x,
966 pos.bottom() - radius.bottom_right_y,
967 radius.bottom_right_x,
968 radius.bottom_right_y,
970 M_PI / 2.0, false);
973 cairo_line_to(cr, pos.left() - radius.bottom_left_x, pos.bottom());
975 if(radius.bottom_left_x && radius.bottom_left_y)
977 add_path_arc(cr,
978 pos.left() + radius.bottom_left_x,
979 pos.bottom() - radius.bottom_left_y,
980 radius.bottom_left_x,
981 radius.bottom_left_y,
982 M_PI / 2.0,
983 M_PI, false);
987 void container_linux::draw_pixbuf(cairo_t* cr, const GdkPixbuf *bmp, int x, int y, int cx, int cy)
989 cairo_save(cr);
992 cairo_matrix_t flib_m;
993 cairo_matrix_init(&flib_m, 1, 0, 0, -1, 0, 0);
995 if(cx != gdk_pixbuf_get_width(bmp) || cy != gdk_pixbuf_get_height(bmp))
997 GdkPixbuf *new_img = gdk_pixbuf_scale_simple(bmp, cx, cy, GDK_INTERP_BILINEAR);
998 gdk_cairo_set_source_pixbuf(cr, new_img, x, y);
999 cairo_paint(cr);
1000 } else
1002 gdk_cairo_set_source_pixbuf(cr, bmp, x, y);
1003 cairo_paint(cr);
1007 cairo_restore(cr);
1010 cairo_surface_t* container_linux::surface_from_pixbuf(const GdkPixbuf *bmp)
1012 cairo_surface_t* ret;
1014 if(gdk_pixbuf_get_has_alpha(bmp))
1016 ret = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, gdk_pixbuf_get_width(bmp), gdk_pixbuf_get_height(bmp));
1017 } else
1019 ret = cairo_image_surface_create(CAIRO_FORMAT_RGB24, gdk_pixbuf_get_width(bmp), gdk_pixbuf_get_height(bmp));
1022 // Cairo::RefPtr<Cairo::Surface> surface(new Cairo::Surface(ret, false));
1023 // Cairo::RefPtr<Cairo::Context> ctx = Cairo::Context::create(surface);
1024 // Gdk::Cairo::set_source_pixbuf(ctx, bmp, 0.0, 0.0);
1025 cairo_t *ctx = cairo_create(ret);
1026 cairo_paint(ctx);
1027 cairo_destroy(ctx);
1029 return ret;
1032 void container_linux::get_media_features(litehtml::media_features& media) const
1034 litehtml::position client;
1035 get_client_rect(client);
1036 media.type = litehtml::media_type_screen;
1037 media.width = client.width;
1038 media.height = client.height;
1039 media.device_width = gdk_screen_width();
1040 media.device_height = gdk_screen_height();
1041 media.color = 8;
1042 media.monochrome = 0;
1043 media.color_index = 256;
1044 media.resolution = 96;
1047 void container_linux::get_language(litehtml::string& language, litehtml::string& culture) const
1049 language = "en";
1050 culture = "";
1053 void container_linux::link(const std::shared_ptr<litehtml::document> &ptr, const litehtml::element::ptr& el)