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 
container_linux(void)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 	g_rec_mutex_init(&m_images_lock);
39 }
40 
~container_linux(void)41 container_linux::~container_linux(void)
42 {
43 	clear_images();
44 	cairo_surface_destroy(m_temp_surface);
45 	cairo_destroy(m_temp_cr);
46 	g_rec_mutex_clear(&m_images_lock);
47 }
48 
pt_to_px(int pt)49 int container_linux::pt_to_px( int pt )
50 {
51 	GdkScreen* screen = gdk_screen_get_default();
52 	double dpi = gdk_screen_get_resolution(screen);
53 
54 	return (int) ((double) pt * dpi / 72.0);
55 }
56 
draw_list_marker(litehtml::uint_ptr hdc,const litehtml::list_marker & marker)57 void container_linux::draw_list_marker( litehtml::uint_ptr hdc, const litehtml::list_marker& marker )
58 {
59 	if(!marker.image.empty())
60 	{
61 		/*litehtml::tstring url;
62 		make_url(marker.image.c_str(), marker.baseurl, url);
63 
64 		lock_images_cache();
65 		images_map::iterator img_i = m_images.find(url.c_str());
66 		if(img_i != m_images.end())
67 		{
68 			if(img_i->second)
69 			{
70 				draw_txdib((cairo_t*) hdc, img_i->second, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height);
71 			}
72 		}
73 		unlock_images_cache();*/
74 	} else
75 	{
76 		switch(marker.marker_type)
77 		{
78 		case litehtml::list_style_type_circle:
79 			{
80 				draw_ellipse((cairo_t*) hdc, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height, marker.color, 0.5);
81 			}
82 			break;
83 		case litehtml::list_style_type_disc:
84 			{
85 				fill_ellipse((cairo_t*) hdc, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height, marker.color);
86 			}
87 			break;
88 		case litehtml::list_style_type_square:
89 			if(hdc)
90 			{
91 				cairo_t* cr = (cairo_t*) hdc;
92 				cairo_save(cr);
93 
94 				cairo_new_path(cr);
95 				cairo_rectangle(cr, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height);
96 
97 				set_color(cr, marker.color);
98 				cairo_fill(cr);
99 				cairo_restore(cr);
100 			}
101 			break;
102 		default:
103 			/*do nothing*/
104 			break;
105 		}
106 	}
107 }
108 
draw_background(litehtml::uint_ptr hdc,const litehtml::background_paint & bg)109 void container_linux::draw_background( litehtml::uint_ptr hdc, const litehtml::background_paint& bg )
110 {
111 	cairo_t* cr = (cairo_t*) hdc;
112 	cairo_save(cr);
113 	apply_clip(cr);
114 
115 	rounded_rectangle(cr, bg.border_box, bg.border_radius);
116 	cairo_clip(cr);
117 
118 	cairo_rectangle(cr, bg.clip_box.x, bg.clip_box.y, bg.clip_box.width, bg.clip_box.height);
119 	cairo_clip(cr);
120 
121 	if(bg.color.alpha)
122 	{
123 		set_color(cr, bg.color);
124 		cairo_paint(cr);
125 	}
126 
127 	litehtml::tstring url;
128 	make_url(bg.image.c_str(), bg.baseurl.c_str(), url);
129 
130 	const image *img_i = NULL;
131 
132 	lock_images_cache();
133 
134 	for (auto ii = m_images.cbegin(); ii != m_images.cend(); ++ii) {
135 		const image *i = &(*ii);
136 		if (i->first == url) {
137 			img_i = i;
138 			break;
139 		}
140 	}
141 
142 	if(img_i != NULL && img_i->second)
143 	{
144 		GdkPixbuf *bgbmp = img_i->second;
145 
146 		GdkPixbuf *new_img;
147 		if(bg.image_size.width != gdk_pixbuf_get_width(bgbmp) || bg.image_size.height != gdk_pixbuf_get_height(bgbmp))
148 		{
149 			new_img = gdk_pixbuf_scale_simple(bgbmp, bg.image_size.width, bg.image_size.height, GDK_INTERP_BILINEAR);
150 			bgbmp = new_img;
151 		}
152 
153 		cairo_surface_t* img = surface_from_pixbuf(bgbmp);
154 		cairo_pattern_t *pattern = cairo_pattern_create_for_surface(img);
155 		cairo_matrix_t flib_m;
156 		cairo_matrix_init_identity(&flib_m);
157 		cairo_matrix_translate(&flib_m, -bg.position_x, -bg.position_y);
158 		cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
159 		cairo_pattern_set_matrix (pattern, &flib_m);
160 
161 		switch(bg.repeat)
162 		{
163 		case litehtml::background_repeat_no_repeat:
164 			draw_pixbuf(cr, bgbmp, bg.position_x, bg.position_y, gdk_pixbuf_get_width(bgbmp), gdk_pixbuf_get_height(bgbmp));
165 			break;
166 
167 		case litehtml::background_repeat_repeat_x:
168 			cairo_set_source(cr, pattern);
169 			cairo_rectangle(cr, bg.clip_box.left(), bg.position_y, bg.clip_box.width, gdk_pixbuf_get_height(bgbmp));
170 			cairo_fill(cr);
171 			break;
172 
173 		case litehtml::background_repeat_repeat_y:
174 			cairo_set_source(cr, pattern);
175 			cairo_rectangle(cr, bg.position_x, bg.clip_box.top(), gdk_pixbuf_get_width(bgbmp), bg.clip_box.height);
176 			cairo_fill(cr);
177 			break;
178 
179 		case litehtml::background_repeat_repeat:
180 			cairo_set_source(cr, pattern);
181 			cairo_rectangle(cr, bg.clip_box.left(), bg.clip_box.top(), bg.clip_box.width, bg.clip_box.height);
182 			cairo_fill(cr);
183 			break;
184 		}
185 
186 		cairo_pattern_destroy(pattern);
187 		cairo_surface_destroy(img);
188 
189 	}
190 
191 	unlock_images_cache();
192 	cairo_restore(cr);
193 }
194 
make_url(const litehtml::tchar_t * url,const litehtml::tchar_t * basepath,litehtml::tstring & out)195 void container_linux::make_url(const litehtml::tchar_t* url,	const litehtml::tchar_t* basepath, litehtml::tstring& out)
196 {
197 	out = url;
198 }
199 
add_path_arc(cairo_t * cr,double x,double y,double rx,double ry,double a1,double a2,bool neg)200 void container_linux::add_path_arc(cairo_t* cr, double x, double y, double rx, double ry, double a1, double a2, bool neg)
201 {
202 	if(rx > 0 && ry > 0)
203 	{
204 
205 		cairo_save(cr);
206 
207 		cairo_translate(cr, x, y);
208 		cairo_scale(cr, 1, ry / rx);
209 		cairo_translate(cr, -x, -y);
210 
211 		if(neg)
212 		{
213 			cairo_arc_negative(cr, x, y, rx, a1, a2);
214 		} else
215 		{
216 			cairo_arc(cr, x, y, rx, a1, a2);
217 		}
218 
219 		cairo_restore(cr);
220 	} else
221 	{
222 		cairo_move_to(cr, x, y);
223 	}
224 }
225 
draw_borders(litehtml::uint_ptr hdc,const litehtml::borders & borders,const litehtml::position & draw_pos,bool root)226 void container_linux::draw_borders(litehtml::uint_ptr hdc, const litehtml::borders& borders, const litehtml::position& draw_pos, bool root)
227 {
228 	cairo_t* cr = (cairo_t*) hdc;
229 	cairo_save(cr);
230 	apply_clip(cr);
231 
232 	cairo_new_path(cr);
233 
234 	int bdr_top		= 0;
235 	int bdr_bottom	= 0;
236 	int bdr_left	= 0;
237 	int bdr_right	= 0;
238 
239 	if(borders.top.width != 0 && borders.top.style > litehtml::border_style_hidden)
240 	{
241 		bdr_top = (int) borders.top.width;
242 	}
243 	if(borders.bottom.width != 0 && borders.bottom.style > litehtml::border_style_hidden)
244 	{
245 		bdr_bottom = (int) borders.bottom.width;
246 	}
247 	if(borders.left.width != 0 && borders.left.style > litehtml::border_style_hidden)
248 	{
249 		bdr_left = (int) borders.left.width;
250 	}
251 	if(borders.right.width != 0 && borders.right.style > litehtml::border_style_hidden)
252 	{
253 		bdr_right = (int) borders.right.width;
254 	}
255 
256 	// draw right border
257 	if(bdr_right)
258 	{
259 		set_color(cr, borders.right.color);
260 
261 		double r_top	= borders.radius.top_right_x;
262 		double r_bottom	= borders.radius.bottom_right_x;
263 
264 		if(r_top)
265 		{
266 			double end_angle	= 2 * M_PI;
267 			double start_angle	= end_angle - M_PI / 2.0  / ((double) bdr_top / (double) bdr_right + 1);
268 
269 			add_path_arc(cr,
270 				draw_pos.right() - r_top,
271 				draw_pos.top() + r_top,
272 				r_top - bdr_right,
273 				r_top - bdr_right + (bdr_right - bdr_top),
274 				end_angle,
275 				start_angle, true);
276 
277 			add_path_arc(cr,
278 				draw_pos.right() - r_top,
279 				draw_pos.top() + r_top,
280 				r_top,
281 				r_top,
282 				start_angle,
283 				end_angle, false);
284 		} else
285 		{
286 			cairo_move_to(cr, draw_pos.right() - bdr_right, draw_pos.top() + bdr_top);
287 			cairo_line_to(cr, draw_pos.right(), draw_pos.top());
288 		}
289 
290 		if(r_bottom)
291 		{
292 			cairo_line_to(cr, draw_pos.right(),	draw_pos.bottom() - r_bottom);
293 
294 			double start_angle	= 0;
295 			double end_angle	= start_angle + M_PI / 2.0  / ((double) bdr_bottom / (double) bdr_right + 1);
296 
297 			add_path_arc(cr,
298 				draw_pos.right() - r_bottom,
299 				draw_pos.bottom() - r_bottom,
300 				r_bottom,
301 				r_bottom,
302 				start_angle,
303 				end_angle, false);
304 
305 			add_path_arc(cr,
306 				draw_pos.right() - r_bottom,
307 				draw_pos.bottom() - r_bottom,
308 				r_bottom - bdr_right,
309 				r_bottom - bdr_right + (bdr_right - bdr_bottom),
310 				end_angle,
311 				start_angle, true);
312 		} else
313 		{
314 			cairo_line_to(cr, draw_pos.right(),	draw_pos.bottom());
315 			cairo_line_to(cr, draw_pos.right() - bdr_right,	draw_pos.bottom() - bdr_bottom);
316 		}
317 
318 		cairo_fill(cr);
319 	}
320 
321 	// draw bottom border
322 	if(bdr_bottom)
323 	{
324 		set_color(cr, borders.bottom.color);
325 
326 		double r_left	= borders.radius.bottom_left_x;
327 		double r_right	= borders.radius.bottom_right_x;
328 
329 		if(r_left)
330 		{
331 			double start_angle	= M_PI / 2.0;
332 			double end_angle	= start_angle + M_PI / 2.0  / ((double) bdr_left / (double) bdr_bottom + 1);
333 
334 			add_path_arc(cr,
335 				draw_pos.left() + r_left,
336 				draw_pos.bottom() - r_left,
337 				r_left - bdr_bottom + (bdr_bottom - bdr_left),
338 				r_left - bdr_bottom,
339 				start_angle,
340 				end_angle, false);
341 
342 			add_path_arc(cr,
343 				draw_pos.left() + r_left,
344 				draw_pos.bottom() - r_left,
345 				r_left,
346 				r_left,
347 				end_angle,
348 				start_angle, true);
349 		} else
350 		{
351 			cairo_move_to(cr, draw_pos.left(), draw_pos.bottom());
352 			cairo_line_to(cr, draw_pos.left() + bdr_left, draw_pos.bottom() - bdr_bottom);
353 		}
354 
355 		if(r_right)
356 		{
357 			cairo_line_to(cr, draw_pos.right() - r_right,	draw_pos.bottom());
358 
359 			double end_angle	= M_PI / 2.0;
360 			double start_angle	= end_angle - M_PI / 2.0  / ((double) bdr_right / (double) bdr_bottom + 1);
361 
362 			add_path_arc(cr,
363 				draw_pos.right() - r_right,
364 				draw_pos.bottom() - r_right,
365 				r_right,
366 				r_right,
367 				end_angle,
368 				start_angle, true);
369 
370 			add_path_arc(cr,
371 				draw_pos.right() - r_right,
372 				draw_pos.bottom() - r_right,
373 				r_right - bdr_bottom + (bdr_bottom - bdr_right),
374 				r_right - bdr_bottom,
375 				start_angle,
376 				end_angle, false);
377 		} else
378 		{
379 			cairo_line_to(cr, draw_pos.right() - bdr_right,	draw_pos.bottom() - bdr_bottom);
380 			cairo_line_to(cr, draw_pos.right(),	draw_pos.bottom());
381 		}
382 
383 		cairo_fill(cr);
384 	}
385 
386 	// draw top border
387 	if(bdr_top)
388 	{
389 		set_color(cr, borders.top.color);
390 
391 		double r_left	= borders.radius.top_left_x;
392 		double r_right	= borders.radius.top_right_x;
393 
394 		if(r_left)
395 		{
396 			double end_angle	= M_PI * 3.0 / 2.0;
397 			double start_angle	= end_angle - M_PI / 2.0  / ((double) bdr_left / (double) bdr_top + 1);
398 
399 			add_path_arc(cr,
400 				draw_pos.left() + r_left,
401 				draw_pos.top() + r_left,
402 				r_left,
403 				r_left,
404 				end_angle,
405 				start_angle, true);
406 
407 			add_path_arc(cr,
408 				draw_pos.left() + r_left,
409 				draw_pos.top() + r_left,
410 				r_left - bdr_top + (bdr_top - bdr_left),
411 				r_left - bdr_top,
412 				start_angle,
413 				end_angle, false);
414 		} else
415 		{
416 			cairo_move_to(cr, draw_pos.left(), draw_pos.top());
417 			cairo_line_to(cr, draw_pos.left() + bdr_left, draw_pos.top() + bdr_top);
418 		}
419 
420 		if(r_right)
421 		{
422 			cairo_line_to(cr, draw_pos.right() - r_right,	draw_pos.top() + bdr_top);
423 
424 			double start_angle	= M_PI * 3.0 / 2.0;
425 			double end_angle	= start_angle + M_PI / 2.0  / ((double) bdr_right / (double) bdr_top + 1);
426 
427 			add_path_arc(cr,
428 				draw_pos.right() - r_right,
429 				draw_pos.top() + r_right,
430 				r_right - bdr_top + (bdr_top - bdr_right),
431 				r_right - bdr_top,
432 				start_angle,
433 				end_angle, false);
434 
435 			add_path_arc(cr,
436 				draw_pos.right() - r_right,
437 				draw_pos.top() + r_right,
438 				r_right,
439 				r_right,
440 				end_angle,
441 				start_angle, true);
442 		} else
443 		{
444 			cairo_line_to(cr, draw_pos.right() - bdr_right,	draw_pos.top() + bdr_top);
445 			cairo_line_to(cr, draw_pos.right(),	draw_pos.top());
446 		}
447 
448 		cairo_fill(cr);
449 	}
450 
451 	// draw left border
452 	if(bdr_left)
453 	{
454 		set_color(cr, borders.left.color);
455 
456 		double r_top	= borders.radius.top_left_x;
457 		double r_bottom	= borders.radius.bottom_left_x;
458 
459 		if(r_top)
460 		{
461 			double start_angle	= M_PI;
462 			double end_angle	= start_angle + M_PI / 2.0  / ((double) bdr_top / (double) bdr_left + 1);
463 
464 			add_path_arc(cr,
465 				draw_pos.left() + r_top,
466 				draw_pos.top() + r_top,
467 				r_top - bdr_left,
468 				r_top - bdr_left + (bdr_left - bdr_top),
469 				start_angle,
470 				end_angle, false);
471 
472 			add_path_arc(cr,
473 				draw_pos.left() + r_top,
474 				draw_pos.top() + r_top,
475 				r_top,
476 				r_top,
477 				end_angle,
478 				start_angle, true);
479 		} else
480 		{
481 			cairo_move_to(cr, draw_pos.left() + bdr_left, draw_pos.top() + bdr_top);
482 			cairo_line_to(cr, draw_pos.left(), draw_pos.top());
483 		}
484 
485 		if(r_bottom)
486 		{
487 			cairo_line_to(cr, draw_pos.left(),	draw_pos.bottom() - r_bottom);
488 
489 			double end_angle	= M_PI;
490 			double start_angle	= end_angle - M_PI / 2.0  / ((double) bdr_bottom / (double) bdr_left + 1);
491 
492 			add_path_arc(cr,
493 				draw_pos.left() + r_bottom,
494 				draw_pos.bottom() - r_bottom,
495 				r_bottom,
496 				r_bottom,
497 				end_angle,
498 				start_angle, true);
499 
500 			add_path_arc(cr,
501 				draw_pos.left() + r_bottom,
502 				draw_pos.bottom() - r_bottom,
503 				r_bottom - bdr_left,
504 				r_bottom - bdr_left + (bdr_left - bdr_bottom),
505 				start_angle,
506 				end_angle, false);
507 		} else
508 		{
509 			cairo_line_to(cr, draw_pos.left(),	draw_pos.bottom());
510 			cairo_line_to(cr, draw_pos.left() + bdr_left,	draw_pos.bottom() - bdr_bottom);
511 		}
512 
513 		cairo_fill(cr);
514 	}
515 	cairo_restore(cr);
516 }
517 
transform_text(litehtml::tstring & text,litehtml::text_transform tt)518 void container_linux::transform_text(litehtml::tstring& text, litehtml::text_transform tt)
519 {
520 
521 }
522 
set_clip(const litehtml::position & pos,const litehtml::border_radiuses & bdr_radius,bool valid_x,bool valid_y)523 void container_linux::set_clip( const litehtml::position& pos, const litehtml::border_radiuses& bdr_radius, bool valid_x, bool valid_y )
524 {
525 	litehtml::position clip_pos = pos;
526 	litehtml::position client_pos;
527 	get_client_rect(client_pos);
528 	if(!valid_x)
529 	{
530 		clip_pos.x		= client_pos.x;
531 		clip_pos.width	= client_pos.width;
532 	}
533 	if(!valid_y)
534 	{
535 		clip_pos.y		= client_pos.y;
536 		clip_pos.height	= client_pos.height;
537 	}
538 	m_clips.emplace_back(clip_pos, bdr_radius);
539 }
540 
del_clip()541 void container_linux::del_clip()
542 {
543 	if(!m_clips.empty())
544 	{
545 		m_clips.pop_back();
546 	}
547 }
548 
apply_clip(cairo_t * cr)549 void container_linux::apply_clip( cairo_t* cr )
550 {
551 	for(const auto& clip_box : m_clips)
552 	{
553 		rounded_rectangle(cr, clip_box.box, clip_box.radius);
554 		cairo_clip(cr);
555 	}
556 }
557 
draw_ellipse(cairo_t * cr,int x,int y,int width,int height,const litehtml::web_color & color,int line_width)558 void container_linux::draw_ellipse( cairo_t* cr, int x, int y, int width, int height, const litehtml::web_color& color, int line_width )
559 {
560 	if(!cr) return;
561 	cairo_save(cr);
562 
563 	apply_clip(cr);
564 
565 	cairo_new_path(cr);
566 
567 	cairo_translate (cr, x + width / 2.0, y + height / 2.0);
568 	cairo_scale (cr, width / 2.0, height / 2.0);
569 	cairo_arc (cr, 0, 0, 1, 0, 2 * M_PI);
570 
571 	set_color(cr, color);
572 	cairo_set_line_width(cr, line_width);
573 	cairo_stroke(cr);
574 
575 	cairo_restore(cr);
576 }
577 
fill_ellipse(cairo_t * cr,int x,int y,int width,int height,const litehtml::web_color & color)578 void container_linux::fill_ellipse( cairo_t* cr, int x, int y, int width, int height, const litehtml::web_color& color )
579 {
580 	if(!cr) return;
581 	cairo_save(cr);
582 
583 	apply_clip(cr);
584 
585 	cairo_new_path(cr);
586 
587 	cairo_translate (cr, x + width / 2.0, y + height / 2.0);
588 	cairo_scale (cr, width / 2.0, height / 2.0);
589 	cairo_arc (cr, 0, 0, 1, 0, 2 * M_PI);
590 
591 	set_color(cr, color);
592 	cairo_fill(cr);
593 
594 	cairo_restore(cr);
595 }
596 
create_element(const litehtml::tchar_t * tag_name,const litehtml::string_map & attributes,const std::shared_ptr<litehtml::document> & doc)597 std::shared_ptr<litehtml::element>	container_linux::create_element(const litehtml::tchar_t *tag_name,
598 																	  const litehtml::string_map &attributes,
599 																	  const std::shared_ptr<litehtml::document> &doc)
600 {
601 	return 0;
602 }
603 
rounded_rectangle(cairo_t * cr,const litehtml::position & pos,const litehtml::border_radiuses & radius)604 void container_linux::rounded_rectangle( cairo_t* cr, const litehtml::position &pos, const litehtml::border_radiuses &radius )
605 {
606 	cairo_new_path(cr);
607 	if(radius.top_left_x)
608 	{
609 		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);
610 	} else
611 	{
612 		cairo_move_to(cr, pos.left(), pos.top());
613 	}
614 
615 	cairo_line_to(cr, pos.right() - radius.top_right_x, pos.top());
616 
617 	if(radius.top_right_x)
618 	{
619 		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);
620 	}
621 
622 	cairo_line_to(cr, pos.right(), pos.bottom() - radius.bottom_right_x);
623 
624 	if(radius.bottom_right_x)
625 	{
626 		cairo_arc(cr, pos.right() - radius.bottom_right_x, pos.bottom() - radius.bottom_right_x, radius.bottom_right_x, 0, M_PI / 2.0);
627 	}
628 
629 	cairo_line_to(cr, pos.left() - radius.bottom_left_x, pos.bottom());
630 
631 	if(radius.bottom_left_x)
632 	{
633 		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);
634 	}
635 }
636 
draw_pixbuf(cairo_t * cr,const GdkPixbuf * bmp,int x,int y,int cx,int cy)637 void container_linux::draw_pixbuf(cairo_t* cr, const GdkPixbuf *bmp, int x,	int y, int cx, int cy)
638 {
639 	cairo_save(cr);
640 
641 	{
642 		cairo_matrix_t flib_m;
643 		cairo_matrix_init(&flib_m, 1, 0, 0, -1, 0, 0);
644 
645 		if(cx != gdk_pixbuf_get_width(bmp) || cy != gdk_pixbuf_get_height(bmp))
646 		{
647 			GdkPixbuf *new_img = gdk_pixbuf_scale_simple(bmp, cx, cy, GDK_INTERP_BILINEAR);
648 			gdk_cairo_set_source_pixbuf(cr, new_img, x, y);
649 			cairo_paint(cr);
650 		} else
651 		{
652 			gdk_cairo_set_source_pixbuf(cr, bmp, x, y);
653 			cairo_paint(cr);
654 		}
655 	}
656 
657 	cairo_restore(cr);
658 }
659 
surface_from_pixbuf(const GdkPixbuf * bmp)660 cairo_surface_t* container_linux::surface_from_pixbuf(const GdkPixbuf *bmp)
661 {
662 	cairo_surface_t* ret = NULL;
663 
664 	if(gdk_pixbuf_get_has_alpha(bmp))
665 	{
666 		ret = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, gdk_pixbuf_get_width(bmp), gdk_pixbuf_get_height(bmp));
667 	} else
668 	{
669 		ret = cairo_image_surface_create(CAIRO_FORMAT_RGB24, gdk_pixbuf_get_width(bmp), gdk_pixbuf_get_height(bmp));
670 	}
671 
672 //	Cairo::RefPtr<Cairo::Surface> surface(new Cairo::Surface(ret, false));
673 //	Cairo::RefPtr<Cairo::Context> ctx = Cairo::Context::create(surface);
674 //	Gdk::Cairo::set_source_pixbuf(ctx, bmp, 0.0, 0.0);
675 	cairo_t *ctx = cairo_create(ret);
676 	cairo_paint(ctx);
677 	cairo_destroy(ctx);
678 
679 	return ret;
680 }
681 
get_media_features(litehtml::media_features & media) const682 void container_linux::get_media_features(litehtml::media_features& media) const
683 {
684 	litehtml::position client;
685     get_client_rect(client);
686 	media.type			= litehtml::media_type_screen;
687 	media.width			= client.width;
688 	media.height		= client.height;
689 	media.device_width	= gdk_screen_width();
690 	media.device_height	= gdk_screen_height();
691 	media.color			= 8;
692 	media.monochrome	= 0;
693 	media.color_index	= 256;
694 	media.resolution	= 96;
695 }
696 
get_language(litehtml::tstring & language,litehtml::tstring & culture) const697 void container_linux::get_language(litehtml::tstring& language, litehtml::tstring& culture) const
698 {
699 	language = _t("en");
700 	culture = _t("");
701 }
702 
link(const std::shared_ptr<litehtml::document> & ptr,const litehtml::element::ptr & el)703 void container_linux::link(const std::shared_ptr<litehtml::document> &ptr, const litehtml::element::ptr& el)
704 {
705 
706 }
707