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.
20 #include "claws-features.h"
23 #include "container_linux.h"
27 #define _USE_MATH_DEFINES
31 # define M_PI 3.14159265358979323846
34 container_linux::container_linux(void)
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(void)
44 cairo_surface_destroy(m_temp_surface);
45 cairo_destroy(m_temp_cr);
46 g_rec_mutex_clear(&m_images_lock);
49 int container_linux::pt_to_px( int pt )
51 GdkScreen* screen = gdk_screen_get_default();
52 double dpi = gdk_screen_get_resolution(screen);
54 return (int) ((double) pt * dpi / 72.0);
57 void container_linux::draw_list_marker( litehtml::uint_ptr hdc, const litehtml::list_marker& marker )
59 if(!marker.image.empty())
61 /*litehtml::tstring url;
62 make_url(marker.image.c_str(), marker.baseurl, url);
65 images_map::iterator img_i = m_images.find(url.c_str());
66 if(img_i != m_images.end())
70 draw_txdib((cairo_t*) hdc, img_i->second, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height);
73 unlock_images_cache();*/
76 switch(marker.marker_type)
78 case litehtml::list_style_type_circle:
80 draw_ellipse((cairo_t*) hdc, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height, marker.color, 0.5);
83 case litehtml::list_style_type_disc:
85 fill_ellipse((cairo_t*) hdc, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height, marker.color);
88 case litehtml::list_style_type_square:
91 cairo_t* cr = (cairo_t*) hdc;
95 cairo_rectangle(cr, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height);
97 set_color(cr, marker.color);
109 void container_linux::load_image( const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, bool redraw_on_ready )
111 litehtml::tstring url;
112 make_url(src, baseurl, url);
115 for (auto ii = m_images.cbegin(); ii != m_images.cend(); ++ii) {
116 const image *i = &(*ii);
118 if (!strcmp(i->first.c_str(), url.c_str())) {
128 GdkPixbuf *img = get_image(url.c_str(), true);
131 m_images.push_back(std::make_pair(url, img));
141 void container_linux::get_image_size( const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, litehtml::size& sz )
143 litehtml::tstring url;
144 make_url(src, baseurl, url);
146 const image *img = NULL;
148 for (auto ii = m_images.cbegin(); ii != m_images.cend(); ++ii) {
149 const image *i = &(*ii);
150 if (i->first == url) {
159 sz.width = gdk_pixbuf_get_width(img->second);
160 sz.height = gdk_pixbuf_get_height(img->second);
168 void container_linux::draw_background( litehtml::uint_ptr hdc, const litehtml::background_paint& bg )
170 cairo_t* cr = (cairo_t*) hdc;
174 rounded_rectangle(cr, bg.border_box, bg.border_radius);
177 cairo_rectangle(cr, bg.clip_box.x, bg.clip_box.y, bg.clip_box.width, bg.clip_box.height);
182 set_color(cr, bg.color);
186 litehtml::tstring url;
187 make_url(bg.image.c_str(), bg.baseurl.c_str(), url);
191 const image *img_i = NULL;
193 for (auto ii = m_images.cbegin(); ii != m_images.cend(); ++ii) {
194 const image *i = &(*ii);
195 if (i->first == url) {
202 if(img_i != NULL && img_i->second)
204 GdkPixbuf *bgbmp = img_i->second;
207 if(bg.image_size.width != gdk_pixbuf_get_width(bgbmp) || bg.image_size.height != gdk_pixbuf_get_height(bgbmp))
209 new_img = gdk_pixbuf_scale_simple(bgbmp, bg.image_size.width, bg.image_size.height, GDK_INTERP_BILINEAR);
213 cairo_surface_t* img = surface_from_pixbuf(bgbmp);
214 cairo_pattern_t *pattern = cairo_pattern_create_for_surface(img);
215 cairo_matrix_t flib_m;
216 cairo_matrix_init_identity(&flib_m);
217 cairo_matrix_translate(&flib_m, -bg.position_x, -bg.position_y);
218 cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
219 cairo_pattern_set_matrix (pattern, &flib_m);
223 case litehtml::background_repeat_no_repeat:
224 draw_pixbuf(cr, bgbmp, bg.position_x, bg.position_y, gdk_pixbuf_get_width(bgbmp), gdk_pixbuf_get_height(bgbmp));
227 case litehtml::background_repeat_repeat_x:
228 cairo_set_source(cr, pattern);
229 cairo_rectangle(cr, bg.clip_box.left(), bg.position_y, bg.clip_box.width, gdk_pixbuf_get_height(bgbmp));
233 case litehtml::background_repeat_repeat_y:
234 cairo_set_source(cr, pattern);
235 cairo_rectangle(cr, bg.position_x, bg.clip_box.top(), gdk_pixbuf_get_width(bgbmp), bg.clip_box.height);
239 case litehtml::background_repeat_repeat:
240 cairo_set_source(cr, pattern);
241 cairo_rectangle(cr, bg.clip_box.left(), bg.clip_box.top(), bg.clip_box.width, bg.clip_box.height);
246 cairo_pattern_destroy(pattern);
247 cairo_surface_destroy(img);
251 unlock_images_cache();
255 void container_linux::make_url(const litehtml::tchar_t* url, const litehtml::tchar_t* basepath, litehtml::tstring& out)
260 void container_linux::add_path_arc(cairo_t* cr, double x, double y, double rx, double ry, double a1, double a2, bool neg)
267 cairo_translate(cr, x, y);
268 cairo_scale(cr, 1, ry / rx);
269 cairo_translate(cr, -x, -y);
273 cairo_arc_negative(cr, x, y, rx, a1, a2);
276 cairo_arc(cr, x, y, rx, a1, a2);
282 cairo_move_to(cr, x, y);
286 void container_linux::draw_borders(litehtml::uint_ptr hdc, const litehtml::borders& borders, const litehtml::position& draw_pos, bool root)
288 cairo_t* cr = (cairo_t*) hdc;
299 if(borders.top.width != 0 && borders.top.style > litehtml::border_style_hidden)
301 bdr_top = (int) borders.top.width;
303 if(borders.bottom.width != 0 && borders.bottom.style > litehtml::border_style_hidden)
305 bdr_bottom = (int) borders.bottom.width;
307 if(borders.left.width != 0 && borders.left.style > litehtml::border_style_hidden)
309 bdr_left = (int) borders.left.width;
311 if(borders.right.width != 0 && borders.right.style > litehtml::border_style_hidden)
313 bdr_right = (int) borders.right.width;
319 set_color(cr, borders.right.color);
321 double r_top = borders.radius.top_right_x;
322 double r_bottom = borders.radius.bottom_right_x;
326 double end_angle = 2 * M_PI;
327 double start_angle = end_angle - M_PI / 2.0 / ((double) bdr_top / (double) bdr_right + 1);
330 draw_pos.right() - r_top,
331 draw_pos.top() + r_top,
333 r_top - bdr_right + (bdr_right - bdr_top),
338 draw_pos.right() - r_top,
339 draw_pos.top() + r_top,
346 cairo_move_to(cr, draw_pos.right() - bdr_right, draw_pos.top() + bdr_top);
347 cairo_line_to(cr, draw_pos.right(), draw_pos.top());
352 cairo_line_to(cr, draw_pos.right(), draw_pos.bottom() - r_bottom);
354 double start_angle = 0;
355 double end_angle = start_angle + M_PI / 2.0 / ((double) bdr_bottom / (double) bdr_right + 1);
358 draw_pos.right() - r_bottom,
359 draw_pos.bottom() - r_bottom,
366 draw_pos.right() - r_bottom,
367 draw_pos.bottom() - r_bottom,
368 r_bottom - bdr_right,
369 r_bottom - bdr_right + (bdr_right - bdr_bottom),
374 cairo_line_to(cr, draw_pos.right(), draw_pos.bottom());
375 cairo_line_to(cr, draw_pos.right() - bdr_right, draw_pos.bottom() - bdr_bottom);
381 // draw bottom border
384 set_color(cr, borders.bottom.color);
386 double r_left = borders.radius.bottom_left_x;
387 double r_right = borders.radius.bottom_right_x;
391 double start_angle = M_PI / 2.0;
392 double end_angle = start_angle + M_PI / 2.0 / ((double) bdr_left / (double) bdr_bottom + 1);
395 draw_pos.left() + r_left,
396 draw_pos.bottom() - r_left,
397 r_left - bdr_bottom + (bdr_bottom - bdr_left),
403 draw_pos.left() + r_left,
404 draw_pos.bottom() - r_left,
411 cairo_move_to(cr, draw_pos.left(), draw_pos.bottom());
412 cairo_line_to(cr, draw_pos.left() + bdr_left, draw_pos.bottom() - bdr_bottom);
417 cairo_line_to(cr, draw_pos.right() - r_right, draw_pos.bottom());
419 double end_angle = M_PI / 2.0;
420 double start_angle = end_angle - M_PI / 2.0 / ((double) bdr_right / (double) bdr_bottom + 1);
423 draw_pos.right() - r_right,
424 draw_pos.bottom() - r_right,
431 draw_pos.right() - r_right,
432 draw_pos.bottom() - r_right,
433 r_right - bdr_bottom + (bdr_bottom - bdr_right),
434 r_right - bdr_bottom,
439 cairo_line_to(cr, draw_pos.right() - bdr_right, draw_pos.bottom() - bdr_bottom);
440 cairo_line_to(cr, draw_pos.right(), draw_pos.bottom());
449 set_color(cr, borders.top.color);
451 double r_left = borders.radius.top_left_x;
452 double r_right = borders.radius.top_right_x;
456 double end_angle = M_PI * 3.0 / 2.0;
457 double start_angle = end_angle - M_PI / 2.0 / ((double) bdr_left / (double) bdr_top + 1);
460 draw_pos.left() + r_left,
461 draw_pos.top() + r_left,
468 draw_pos.left() + r_left,
469 draw_pos.top() + r_left,
470 r_left - bdr_top + (bdr_top - bdr_left),
476 cairo_move_to(cr, draw_pos.left(), draw_pos.top());
477 cairo_line_to(cr, draw_pos.left() + bdr_left, draw_pos.top() + bdr_top);
482 cairo_line_to(cr, draw_pos.right() - r_right, draw_pos.top() + bdr_top);
484 double start_angle = M_PI * 3.0 / 2.0;
485 double end_angle = start_angle + M_PI / 2.0 / ((double) bdr_right / (double) bdr_top + 1);
488 draw_pos.right() - r_right,
489 draw_pos.top() + r_right,
490 r_right - bdr_top + (bdr_top - bdr_right),
496 draw_pos.right() - r_right,
497 draw_pos.top() + r_right,
504 cairo_line_to(cr, draw_pos.right() - bdr_right, draw_pos.top() + bdr_top);
505 cairo_line_to(cr, draw_pos.right(), draw_pos.top());
514 set_color(cr, borders.left.color);
516 double r_top = borders.radius.top_left_x;
517 double r_bottom = borders.radius.bottom_left_x;
521 double start_angle = M_PI;
522 double end_angle = start_angle + M_PI / 2.0 / ((double) bdr_top / (double) bdr_left + 1);
525 draw_pos.left() + r_top,
526 draw_pos.top() + r_top,
528 r_top - bdr_left + (bdr_left - bdr_top),
533 draw_pos.left() + r_top,
534 draw_pos.top() + r_top,
541 cairo_move_to(cr, draw_pos.left() + bdr_left, draw_pos.top() + bdr_top);
542 cairo_line_to(cr, draw_pos.left(), draw_pos.top());
547 cairo_line_to(cr, draw_pos.left(), draw_pos.bottom() - r_bottom);
549 double end_angle = M_PI;
550 double start_angle = end_angle - M_PI / 2.0 / ((double) bdr_bottom / (double) bdr_left + 1);
553 draw_pos.left() + r_bottom,
554 draw_pos.bottom() - r_bottom,
561 draw_pos.left() + r_bottom,
562 draw_pos.bottom() - r_bottom,
564 r_bottom - bdr_left + (bdr_left - bdr_bottom),
569 cairo_line_to(cr, draw_pos.left(), draw_pos.bottom());
570 cairo_line_to(cr, draw_pos.left() + bdr_left, draw_pos.bottom() - bdr_bottom);
578 void container_linux::transform_text(litehtml::tstring& text, litehtml::text_transform tt)
583 void container_linux::set_clip( const litehtml::position& pos, const litehtml::border_radiuses& bdr_radius, bool valid_x, bool valid_y )
585 litehtml::position clip_pos = pos;
586 litehtml::position client_pos;
587 get_client_rect(client_pos);
590 clip_pos.x = client_pos.x;
591 clip_pos.width = client_pos.width;
595 clip_pos.y = client_pos.y;
596 clip_pos.height = client_pos.height;
598 m_clips.emplace_back(clip_pos, bdr_radius);
601 void container_linux::del_clip()
609 void container_linux::apply_clip( cairo_t* cr )
611 for(const auto& clip_box : m_clips)
613 rounded_rectangle(cr, clip_box.box, clip_box.radius);
618 void container_linux::draw_ellipse( cairo_t* cr, int x, int y, int width, int height, const litehtml::web_color& color, int line_width )
627 cairo_translate (cr, x + width / 2.0, y + height / 2.0);
628 cairo_scale (cr, width / 2.0, height / 2.0);
629 cairo_arc (cr, 0, 0, 1, 0, 2 * M_PI);
631 set_color(cr, color);
632 cairo_set_line_width(cr, line_width);
638 void container_linux::fill_ellipse( cairo_t* cr, int x, int y, int width, int height, const litehtml::web_color& color )
647 cairo_translate (cr, x + width / 2.0, y + height / 2.0);
648 cairo_scale (cr, width / 2.0, height / 2.0);
649 cairo_arc (cr, 0, 0, 1, 0, 2 * M_PI);
651 set_color(cr, color);
657 void container_linux::clear_images()
661 for(auto i = m_images.begin(); i != m_images.end(); ++i) {
665 g_object_unref(img->second);
671 unlock_images_cache();
674 gint container_linux::clear_images(gint desired_size)
681 /* First, tally up size of all the stored GdkPixbufs and
682 * deallocate those which make the total size be above
683 * the desired_size limit. We will remove their list
685 for (auto i = m_images.rbegin(); i != m_images.rend(); ++i) {
689 if (img->second == NULL)
692 cursize = gdk_pixbuf_get_byte_length(img->second);
694 if (size + cursize > desired_size) {
695 g_object_unref(img->second);
703 /* Remove elements whose GdkPixbuf pointers point to NULL. */
704 m_images.remove_if([&](image _img) -> bool {
705 if (_img.second == NULL)
710 unlock_images_cache();
715 std::shared_ptr<litehtml::element> container_linux::create_element(const litehtml::tchar_t *tag_name,
716 const litehtml::string_map &attributes,
717 const std::shared_ptr<litehtml::document> &doc)
722 void container_linux::rounded_rectangle( cairo_t* cr, const litehtml::position &pos, const litehtml::border_radiuses &radius )
725 if(radius.top_left_x)
727 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);
730 cairo_move_to(cr, pos.left(), pos.top());
733 cairo_line_to(cr, pos.right() - radius.top_right_x, pos.top());
735 if(radius.top_right_x)
737 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);
740 cairo_line_to(cr, pos.right(), pos.bottom() - radius.bottom_right_x);
742 if(radius.bottom_right_x)
744 cairo_arc(cr, pos.right() - radius.bottom_right_x, pos.bottom() - radius.bottom_right_x, radius.bottom_right_x, 0, M_PI / 2.0);
747 cairo_line_to(cr, pos.left() - radius.bottom_left_x, pos.bottom());
749 if(radius.bottom_left_x)
751 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);
755 void container_linux::draw_pixbuf(cairo_t* cr, const GdkPixbuf *bmp, int x, int y, int cx, int cy)
760 cairo_matrix_t flib_m;
761 cairo_matrix_init(&flib_m, 1, 0, 0, -1, 0, 0);
763 if(cx != gdk_pixbuf_get_width(bmp) || cy != gdk_pixbuf_get_height(bmp))
765 GdkPixbuf *new_img = gdk_pixbuf_scale_simple(bmp, cx, cy, GDK_INTERP_BILINEAR);
766 gdk_cairo_set_source_pixbuf(cr, new_img, x, y);
770 gdk_cairo_set_source_pixbuf(cr, bmp, x, y);
778 cairo_surface_t* container_linux::surface_from_pixbuf(const GdkPixbuf *bmp)
780 cairo_surface_t* ret = NULL;
782 if(gdk_pixbuf_get_has_alpha(bmp))
784 ret = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, gdk_pixbuf_get_width(bmp), gdk_pixbuf_get_height(bmp));
787 ret = cairo_image_surface_create(CAIRO_FORMAT_RGB24, gdk_pixbuf_get_width(bmp), gdk_pixbuf_get_height(bmp));
790 // Cairo::RefPtr<Cairo::Surface> surface(new Cairo::Surface(ret, false));
791 // Cairo::RefPtr<Cairo::Context> ctx = Cairo::Context::create(surface);
792 // Gdk::Cairo::set_source_pixbuf(ctx, bmp, 0.0, 0.0);
793 cairo_t *ctx = cairo_create(ret);
800 void container_linux::get_media_features(litehtml::media_features& media) const
802 litehtml::position client;
803 get_client_rect(client);
804 media.type = litehtml::media_type_screen;
805 media.width = client.width;
806 media.height = client.height;
807 media.device_width = gdk_screen_width();
808 media.device_height = gdk_screen_height();
810 media.monochrome = 0;
811 media.color_index = 256;
812 media.resolution = 96;
815 void container_linux::get_language(litehtml::tstring& language, litehtml::tstring& culture) const
821 void container_linux::link(const std::shared_ptr<litehtml::document> &ptr, const litehtml::element::ptr& el)