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"
24 #include "container_linux_images.h"
31 # define M_PI 3.14159265358979323846
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()
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
);
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;
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
;
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
;
130 pango_font_description_free(fnt
->font
);
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
;
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
);
187 if(fnt
->underline
|| fnt
->strikeout
)
189 tw
= text_width(text
, hFont
);
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);
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);
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
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);
235 images_map::iterator img_i = m_images.find(url.c_str());
236 if(img_i != m_images.end())
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();*/
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);
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
);
258 case litehtml::list_style_type_square
:
261 auto* cr
= (cairo_t
*) hdc
;
265 cairo_rectangle(cr
, marker
.pos
.x
, marker
.pos
.y
, marker
.pos
.width
, marker
.pos
.height
);
267 set_color(cr
, marker
.color
);
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;
286 gettimeofday(&last
, NULL
);
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
);
297 m_images
.insert(std::make_pair(src
, std::make_pair(pixbuf
, last
)));
299 unlock_images_cache();
302 if (!lh_prefs_get()->enable_remote_content
) {
303 debug_print("blocking download of image from '%s'\n", src
);
304 unlock_images_cache();
309 m_images
.insert(std::make_pair(url
, std::make_pair((GdkPixbuf
*)NULL
, last
)));
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();
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
);
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
);
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
;
367 const auto& bg
= bgvec
.back();
369 rounded_rectangle(cr
, bg
.border_box
, bg
.border_radius
);
372 cairo_rectangle(cr
, bg
.clip_box
.x
, bg
.clip_box
.y
, bg
.clip_box
.width
, bg
.clip_box
.height
);
377 set_color(cr
, bg
.color
);
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
);
391 make_url(bg
.image
.c_str(), bg
.baseurl
.c_str(), url
);
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
);
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
);
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
));
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
));
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
);
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
);
439 cairo_pattern_destroy(pattern
);
440 cairo_surface_destroy(img
);
443 g_object_unref(new_img
);
446 unlock_images_cache();
452 void container_linux::make_url(const char* url
, const char* basepath
, litehtml::string
& out
)
457 void container_linux::add_path_arc(cairo_t
* cr
, double x
, double y
, double rx
, double ry
, double a1
, double a2
, bool neg
)
464 cairo_translate(cr
, x
, y
);
465 cairo_scale(cr
, 1, ry
/ rx
);
466 cairo_translate(cr
, -x
, -y
);
470 cairo_arc_negative(cr
, x
, y
, rx
, a1
, a2
);
473 cairo_arc(cr
, x
, y
, rx
, a1
, a2
);
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
;
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
;
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);
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
),
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
,
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);
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
,
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
),
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
);
575 // draw bottom border
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);
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
,
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
,
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);
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
,
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
,
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());
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);
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
,
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
,
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);
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
,
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
,
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());
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);
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
),
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
,
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);
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
,
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
),
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
);
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()
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
);
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;
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
);
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;
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
);
829 void container_linux::clear_images()
833 for(auto i
= m_images
.begin(); i
!= m_images
.end(); ++i
) {
834 if (i
->second
.first
) {
835 g_object_unref(i
->second
.first
);
841 unlock_images_cache();
844 gint
container_linux::clear_images(gsize desired_size
)
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
);
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
) {
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());
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());
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
);
911 unlock_images_cache();
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
)
930 void container_linux::rounded_rectangle( cairo_t
* cr
, const litehtml::position
&pos
, const litehtml::border_radiuses
&radius
)
933 if(radius
.top_left_x
&& radius
.top_left_y
)
936 pos
.left() + radius
.top_left_x
,
937 pos
.top() + radius
.top_left_y
,
941 M_PI
* 3.0 / 2.0, false);
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
)
952 pos
.right() - radius
.top_right_x
,
953 pos
.top() + radius
.top_right_y
,
960 cairo_line_to(cr
, pos
.right(), pos
.bottom() - radius
.bottom_right_x
);
962 if(radius
.bottom_right_x
&& radius
.bottom_right_y
)
965 pos
.right() - radius
.bottom_right_x
,
966 pos
.bottom() - radius
.bottom_right_y
,
967 radius
.bottom_right_x
,
968 radius
.bottom_right_y
,
973 cairo_line_to(cr
, pos
.left() - radius
.bottom_left_x
, pos
.bottom());
975 if(radius
.bottom_left_x
&& radius
.bottom_left_y
)
978 pos
.left() + radius
.bottom_left_x
,
979 pos
.bottom() - radius
.bottom_left_y
,
980 radius
.bottom_left_x
,
981 radius
.bottom_left_y
,
987 void container_linux::draw_pixbuf(cairo_t
* cr
, const GdkPixbuf
*bmp
, int x
, int y
, int cx
, int cy
)
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
);
1002 gdk_cairo_set_source_pixbuf(cr
, bmp
, x
, y
);
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
));
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
);
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();
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
1053 void container_linux::link(const std::shared_ptr
<litehtml::document
> &ptr
, const litehtml::element::ptr
& el
)