1 #include "cairo_container.h"
2 #define _USE_MATH_DEFINES
3 #include <math.h>
4 #include "cairo_font.h"
5 #include <strsafe.h>
6 
cairo_container(void)7 cairo_container::cairo_container(void)
8 {
9 	m_temp_surface	= cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 2, 2);
10 	m_temp_cr		= cairo_create(m_temp_surface);
11 	m_font_link		= NULL;
12 	CoCreateInstance(CLSID_CMultiLanguage, NULL, CLSCTX_ALL, IID_IMLangFontLink2, (void**) &m_font_link);
13 	InitializeCriticalSection(&m_img_sync);
14 }
15 
~cairo_container(void)16 cairo_container::~cairo_container(void)
17 {
18 	clear_images();
19 	if(m_font_link)
20 	{
21 		m_font_link->Release();
22 	}
23 	cairo_surface_destroy(m_temp_surface);
24 	cairo_destroy(m_temp_cr);
25 	DeleteCriticalSection(&m_img_sync);
26 }
27 
create_font(const litehtml::tchar_t * faceName,int size,int weight,litehtml::font_style italic,unsigned int decoration,litehtml::font_metrics * fm)28 litehtml::uint_ptr cairo_container::create_font( const litehtml::tchar_t* faceName, int size, int weight, litehtml::font_style italic, unsigned int decoration, litehtml::font_metrics* fm )
29 {
30 	std::wstring fnt_name = L"sans-serif";
31 
32 	litehtml::string_vector fonts;
33 	litehtml::split_string(faceName, fonts, _t(","));
34 	if(!fonts.empty())
35 	{
36 		litehtml::trim(fonts[0]);
37 #ifdef LITEHTML_UTF8
38 		wchar_t* f = cairo_font::utf8_to_wchar(fonts[0].c_str());
39 		fnt_name = f;
40 		delete f;
41 #else
42 		fnt_name = fonts[0];
43 		if (fnt_name.front() == '"')
44 		{
45 			fnt_name.erase(0, 1);
46 		}
47 		if (fnt_name.back() == '"')
48 		{
49 			fnt_name.erase(fnt_name.length() - 1, 1);
50 		}
51 #endif
52 	}
53 
54 	cairo_font* fnt = new cairo_font(	m_font_link,
55 										fnt_name.c_str(),
56 										size,
57 										weight,
58 										(italic == litehtml::fontStyleItalic) ? TRUE : FALSE,
59 										(decoration & litehtml::font_decoration_linethrough) ? TRUE : FALSE,
60 										(decoration & litehtml::font_decoration_underline) ? TRUE : FALSE);
61 
62 	cairo_save(m_temp_cr);
63 	fnt->load_metrics(m_temp_cr);
64 
65 	if(fm)
66 	{
67 		fm->ascent		= fnt->metrics().ascent;
68 		fm->descent		= fnt->metrics().descent;
69 		fm->height		= fnt->metrics().height;
70 		fm->x_height	= fnt->metrics().x_height;
71 		if(italic == litehtml::fontStyleItalic || decoration)
72 		{
73 			fm->draw_spaces = true;
74 		} else
75 		{
76 			fm->draw_spaces = false;
77 		}
78 	}
79 
80 	cairo_restore(m_temp_cr);
81 
82 	return (litehtml::uint_ptr) fnt;
83 }
84 
delete_font(litehtml::uint_ptr hFont)85 void cairo_container::delete_font( litehtml::uint_ptr hFont )
86 {
87 	cairo_font* fnt = (cairo_font*) hFont;
88 	if(fnt)
89 	{
90 		delete fnt;
91 	}
92 }
93 
text_width(const litehtml::tchar_t * text,litehtml::uint_ptr hFont)94 int cairo_container::text_width( const litehtml::tchar_t* text, litehtml::uint_ptr hFont )
95 {
96 	cairo_font* fnt = (cairo_font*) hFont;
97 
98 	cairo_save(m_temp_cr);
99 	int ret = fnt->text_width(m_temp_cr, text);
100 	cairo_restore(m_temp_cr);
101 	return ret;
102 }
103 
draw_text(litehtml::uint_ptr hdc,const litehtml::tchar_t * text,litehtml::uint_ptr hFont,litehtml::web_color color,const litehtml::position & pos)104 void cairo_container::draw_text( litehtml::uint_ptr hdc, const litehtml::tchar_t* text, litehtml::uint_ptr hFont, litehtml::web_color color, const litehtml::position& pos )
105 {
106 	if(hFont)
107 	{
108 		cairo_font* fnt = (cairo_font*) hFont;
109 		cairo_t* cr		= (cairo_t*) hdc;
110 		cairo_save(cr);
111 
112 		apply_clip(cr);
113 
114 		int x = pos.left();
115 		int y = pos.bottom() - fnt->metrics().descent;
116 
117 		set_color(cr, color);
118 		fnt->show_text(cr, x, y, text);
119 
120 		cairo_restore(cr);
121 	}
122 }
123 
pt_to_px(int pt)124 int cairo_container::pt_to_px( int pt )
125 {
126 	HDC dc = GetDC(NULL);
127 	int ret = MulDiv(pt, GetDeviceCaps(dc, LOGPIXELSY), 72);
128 	ReleaseDC(NULL, dc);
129 	return ret;
130 }
131 
get_default_font_size() const132 int cairo_container::get_default_font_size() const
133 {
134 	return 16;
135 }
136 
draw_list_marker(litehtml::uint_ptr hdc,const litehtml::list_marker & marker)137 void cairo_container::draw_list_marker( litehtml::uint_ptr hdc, const litehtml::list_marker& marker )
138 {
139 	if(!marker.image.empty())
140 	{
141 		std::wstring url;
142 		t_make_url(marker.image.c_str(), marker.baseurl, url);
143 
144 		lock_images_cache();
145 		images_map::iterator img_i = m_images.find(url.c_str());
146 		if(img_i != m_images.end())
147 		{
148 			if(img_i->second)
149 			{
150 				draw_txdib((cairo_t*)hdc, img_i->second.get(), marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height);
151 			}
152 		}
153 		unlock_images_cache();
154 	} else
155 	{
156 		switch(marker.marker_type)
157 		{
158 		case litehtml::list_style_type_circle:
159 			{
160 				draw_ellipse((cairo_t*) hdc, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height, marker.color, 0.5);
161 			}
162 			break;
163 		case litehtml::list_style_type_disc:
164 			{
165 				fill_ellipse((cairo_t*) hdc, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height, marker.color);
166 			}
167 			break;
168 		case litehtml::list_style_type_square:
169 			if(hdc)
170 			{
171 				cairo_t* cr = (cairo_t*) hdc;
172 				cairo_save(cr);
173 
174 				cairo_new_path(cr);
175 				cairo_rectangle(cr, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height);
176 
177 				set_color(cr, marker.color);
178 				cairo_fill(cr);
179 				cairo_restore(cr);
180 			}
181 			break;
182 		}
183 	}
184 }
185 
load_image(const litehtml::tchar_t * src,const litehtml::tchar_t * baseurl,bool redraw_on_ready)186 void cairo_container::load_image( const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, bool redraw_on_ready )
187 {
188 	std::wstring url;
189 	t_make_url(src, baseurl, url);
190 	lock_images_cache();
191 	if(m_images.find(url.c_str()) == m_images.end())
192 	{
193 		unlock_images_cache();
194 		image_ptr img = get_image(url.c_str(), redraw_on_ready);
195 		lock_images_cache();
196 		m_images[url] = img;
197 		unlock_images_cache();
198 	} else
199 	{
200 		unlock_images_cache();
201 	}
202 
203 }
204 
get_image_size(const litehtml::tchar_t * src,const litehtml::tchar_t * baseurl,litehtml::size & sz)205 void cairo_container::get_image_size( const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, litehtml::size& sz )
206 {
207 	std::wstring url;
208 	t_make_url(src, baseurl, url);
209 
210 	sz.width	= 0;
211 	sz.height	= 0;
212 
213 	lock_images_cache();
214 	images_map::iterator img = m_images.find(url.c_str());
215 	if(img != m_images.end())
216 	{
217 		if(img->second)
218 		{
219 			sz.width	= img->second->getWidth();
220 			sz.height	= img->second->getHeight();
221 		}
222 	}
223 	unlock_images_cache();
224 }
225 
draw_image(litehtml::uint_ptr hdc,const litehtml::tchar_t * src,const litehtml::tchar_t * baseurl,const litehtml::position & pos)226 void cairo_container::draw_image( litehtml::uint_ptr hdc, const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, const litehtml::position& pos )
227 {
228 	cairo_t* cr = (cairo_t*) hdc;
229 	cairo_save(cr);
230 	apply_clip(cr);
231 
232 	std::wstring url;
233 	t_make_url(src, baseurl, url);
234 	lock_images_cache();
235 	images_map::iterator img = m_images.find(url.c_str());
236 	if(img != m_images.end())
237 	{
238 		if(img->second)
239 		{
240 			draw_txdib(cr, img->second.get(), pos.x, pos.y, pos.width, pos.height);
241 		}
242 	}
243 	unlock_images_cache();
244 	cairo_restore(cr);
245 }
246 
draw_background(litehtml::uint_ptr hdc,const litehtml::background_paint & bg)247 void cairo_container::draw_background( litehtml::uint_ptr hdc, const litehtml::background_paint& bg )
248 {
249 	cairo_t* cr = (cairo_t*) hdc;
250 	cairo_save(cr);
251 	apply_clip(cr);
252 
253 	rounded_rectangle(cr, bg.border_box, bg.border_radius);
254 	cairo_clip(cr);
255 
256 	cairo_rectangle(cr, bg.clip_box.x, bg.clip_box.y, bg.clip_box.width, bg.clip_box.height);
257 	cairo_clip(cr);
258 
259 	if(bg.color.alpha)
260 	{
261 		set_color(cr, bg.color);
262 		cairo_paint(cr);
263 	}
264 
265 	std::wstring url;
266 	t_make_url(bg.image.c_str(), bg.baseurl.c_str(), url);
267 
268 	lock_images_cache();
269 	images_map::iterator img_i = m_images.find(url.c_str());
270 	if(img_i != m_images.end() && img_i->second)
271 	{
272 		image_ptr bgbmp = img_i->second;
273 
274 		image_ptr new_img;
275 		if(bg.image_size.width != bgbmp->getWidth() || bg.image_size.height != bgbmp->getHeight())
276 		{
277 			new_img = image_ptr(new CTxDIB);
278 			bgbmp->resample(bg.image_size.width, bg.image_size.height, new_img.get());
279 			bgbmp = new_img;
280 		}
281 
282 
283 		cairo_surface_t* img = cairo_image_surface_create_for_data((unsigned char*) bgbmp->getBits(), CAIRO_FORMAT_ARGB32, bgbmp->getWidth(), bgbmp->getHeight(), bgbmp->getWidth() * 4);
284 		cairo_pattern_t *pattern = cairo_pattern_create_for_surface(img);
285 		cairo_matrix_t flib_m;
286 		cairo_matrix_init(&flib_m, 1, 0, 0, -1, 0, 0);
287 		cairo_matrix_translate(&flib_m, -bg.position_x, -bg.position_y);
288 		cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
289 		cairo_pattern_set_matrix (pattern, &flib_m);
290 
291 		switch(bg.repeat)
292 		{
293 		case litehtml::background_repeat_no_repeat:
294 			draw_txdib(cr, bgbmp.get(), bg.position_x, bg.position_y, bgbmp->getWidth(), bgbmp->getHeight());
295 			break;
296 
297 		case litehtml::background_repeat_repeat_x:
298 			cairo_set_source(cr, pattern);
299 			cairo_rectangle(cr, bg.clip_box.left(), bg.position_y, bg.clip_box.width, bgbmp->getHeight());
300 			cairo_fill(cr);
301 			break;
302 
303 		case litehtml::background_repeat_repeat_y:
304 			cairo_set_source(cr, pattern);
305 			cairo_rectangle(cr, bg.position_x, bg.clip_box.top(), bgbmp->getWidth(), bg.clip_box.height);
306 			cairo_fill(cr);
307 			break;
308 
309 		case litehtml::background_repeat_repeat:
310 			cairo_set_source(cr, pattern);
311 			cairo_rectangle(cr, bg.clip_box.left(), bg.clip_box.top(), bg.clip_box.width, bg.clip_box.height);
312 			cairo_fill(cr);
313 			break;
314 		}
315 
316 		cairo_pattern_destroy(pattern);
317 		cairo_surface_destroy(img);
318 	}
319 	unlock_images_cache();
320 	cairo_restore(cr);
321 }
322 
add_path_arc(cairo_t * cr,double x,double y,double rx,double ry,double a1,double a2,bool neg)323 bool cairo_container::add_path_arc(cairo_t* cr, double x, double y, double rx, double ry, double a1, double a2, bool neg)
324 {
325 	if(rx > 0 && ry > 0)
326 	{
327 		cairo_save(cr);
328 
329 		cairo_translate(cr, x, y);
330 		cairo_scale(cr, 1, ry / rx);
331 		cairo_translate(cr, -x, -y);
332 
333 		if(neg)
334 		{
335 			cairo_arc_negative(cr, x, y, rx, a1, a2);
336 		} else
337 		{
338 			cairo_arc(cr, x, y, rx, a1, a2);
339 		}
340 
341 		cairo_restore(cr);
342 		return true;
343 	}
344 	return false;
345 }
346 
draw_borders(litehtml::uint_ptr hdc,const litehtml::borders & borders,const litehtml::position & draw_pos,bool root)347 void cairo_container::draw_borders( litehtml::uint_ptr hdc, const litehtml::borders& borders, const litehtml::position& draw_pos, bool root )
348 {
349 	cairo_t* cr = (cairo_t*) hdc;
350 	cairo_save(cr);
351 	apply_clip(cr);
352 
353 	cairo_new_path(cr);
354 
355 	int bdr_top		= 0;
356 	int bdr_bottom	= 0;
357 	int bdr_left	= 0;
358 	int bdr_right	= 0;
359 
360 	if(borders.top.width != 0 && borders.top.style > litehtml::border_style_hidden)
361 	{
362 		bdr_top = (int) borders.top.width;
363 	}
364 	if(borders.bottom.width != 0 && borders.bottom.style > litehtml::border_style_hidden)
365 	{
366 		bdr_bottom = (int) borders.bottom.width;
367 	}
368 	if(borders.left.width != 0 && borders.left.style > litehtml::border_style_hidden)
369 	{
370 		bdr_left = (int) borders.left.width;
371 	}
372 	if(borders.right.width != 0 && borders.right.style > litehtml::border_style_hidden)
373 	{
374 		bdr_right = (int) borders.right.width;
375 	}
376 
377 	// draw right border
378 	if (bdr_right)
379 	{
380 		set_color(cr, borders.right.color);
381 
382 		double r_top	= (double) borders.radius.top_right_x;
383 		double r_bottom	= (double) borders.radius.bottom_right_x;
384 
385 		if(r_top)
386 		{
387 			double end_angle	= 2.0 * M_PI;
388 			double start_angle	= end_angle - M_PI / 2.0  / ((double) bdr_top / (double) bdr_right + 0.5);
389 
390 			if (!add_path_arc(cr,
391 					draw_pos.right() - r_top,
392 					draw_pos.top() + r_top,
393 					r_top - bdr_right,
394 					r_top - bdr_right + (bdr_right - bdr_top),
395 					end_angle,
396 					start_angle, true))
397 			{
398 				cairo_move_to(cr, draw_pos.right() - bdr_right, draw_pos.top() + bdr_top);
399 			}
400 
401 			if (!add_path_arc(cr,
402 					draw_pos.right() - r_top,
403 					draw_pos.top() + r_top,
404 					r_top,
405 					r_top,
406 					start_angle,
407 					end_angle, false))
408 			{
409 				cairo_line_to(cr, draw_pos.right(), draw_pos.top());
410 			}
411 		} else
412 		{
413 			cairo_move_to(cr, draw_pos.right() - bdr_right, draw_pos.top() + bdr_top);
414 			cairo_line_to(cr, draw_pos.right(), draw_pos.top());
415 		}
416 
417 		if(r_bottom)
418 		{
419 			cairo_line_to(cr, draw_pos.right(),	draw_pos.bottom() - r_bottom);
420 
421 			double start_angle	= 0;
422 			double end_angle	= start_angle + M_PI / 2.0  / ((double) bdr_bottom / (double) bdr_right + 0.5);
423 
424 			if (!add_path_arc(cr,
425 				draw_pos.right() - r_bottom,
426 				draw_pos.bottom() - r_bottom,
427 				r_bottom,
428 				r_bottom,
429 				start_angle,
430 				end_angle, false))
431 			{
432 				cairo_line_to(cr, draw_pos.right(), draw_pos.bottom());
433 			}
434 
435 			if (!add_path_arc(cr,
436 				draw_pos.right() - r_bottom,
437 				draw_pos.bottom() - r_bottom,
438 				r_bottom - bdr_right,
439 				r_bottom - bdr_right + (bdr_right - bdr_bottom),
440 				end_angle,
441 				start_angle, true))
442 			{
443 				cairo_line_to(cr, draw_pos.right() - bdr_right, draw_pos.bottom() - bdr_bottom);
444 			}
445 		} else
446 		{
447 			cairo_line_to(cr, draw_pos.right(),	draw_pos.bottom());
448 			cairo_line_to(cr, draw_pos.right() - bdr_right,	draw_pos.bottom() - bdr_bottom);
449 		}
450 
451 		cairo_fill(cr);
452 	}
453 
454 	// draw bottom border
455 	if(bdr_bottom)
456 	{
457 		set_color(cr, borders.bottom.color);
458 
459 		double r_left	= borders.radius.bottom_left_x;
460 		double r_right	= borders.radius.bottom_right_x;
461 
462 		if(r_left)
463 		{
464 			double start_angle	= M_PI / 2.0;
465 			double end_angle	= start_angle + M_PI / 2.0  / ((double) bdr_left / (double) bdr_bottom + 0.5);
466 
467 			if (!add_path_arc(cr,
468 				draw_pos.left() + r_left,
469 				draw_pos.bottom() - r_left,
470 				r_left - bdr_bottom + (bdr_bottom - bdr_left),
471 				r_left - bdr_bottom,
472 				start_angle,
473 				end_angle, false))
474 			{
475 				cairo_move_to(cr, draw_pos.left() + bdr_left, draw_pos.bottom() - bdr_bottom);
476 			}
477 
478 			if (!add_path_arc(cr,
479 				draw_pos.left() + r_left,
480 				draw_pos.bottom() - r_left,
481 				r_left,
482 				r_left,
483 				end_angle,
484 				start_angle, true))
485 			{
486 				cairo_line_to(cr, draw_pos.left(), draw_pos.bottom());
487 			}
488 		} else
489 		{
490 			cairo_move_to(cr, draw_pos.left(), draw_pos.bottom());
491 			cairo_line_to(cr, draw_pos.left() + bdr_left, draw_pos.bottom() - bdr_bottom);
492 		}
493 
494 		if(r_right)
495 		{
496 			cairo_line_to(cr, draw_pos.right() - r_right,	draw_pos.bottom());
497 
498 			double end_angle	= M_PI / 2.0;
499 			double start_angle	= end_angle - M_PI / 2.0  / ((double) bdr_right / (double) bdr_bottom + 0.5);
500 
501 			if (!add_path_arc(cr,
502 				draw_pos.right() - r_right,
503 				draw_pos.bottom() - r_right,
504 				r_right,
505 				r_right,
506 				end_angle,
507 				start_angle, true))
508 			{
509 				cairo_line_to(cr, draw_pos.right(), draw_pos.bottom());
510 			}
511 
512 			if (!add_path_arc(cr,
513 				draw_pos.right() - r_right,
514 				draw_pos.bottom() - r_right,
515 				r_right - bdr_bottom + (bdr_bottom - bdr_right),
516 				r_right - bdr_bottom,
517 				start_angle,
518 				end_angle, false))
519 			{
520 				cairo_line_to(cr, draw_pos.right() - bdr_right, draw_pos.bottom() - bdr_bottom);
521 			}
522 		} else
523 		{
524 			cairo_line_to(cr, draw_pos.right() - bdr_right,	draw_pos.bottom() - bdr_bottom);
525 			cairo_line_to(cr, draw_pos.right(),	draw_pos.bottom());
526 		}
527 
528 		cairo_fill(cr);
529 	}
530 
531 	// draw top border
532 	if(bdr_top)
533 	{
534 		set_color(cr, borders.top.color);
535 
536 		double r_left	= borders.radius.top_left_x;
537 		double r_right	= borders.radius.top_right_x;
538 
539 		if(r_left)
540 		{
541 			double end_angle	= M_PI * 3.0 / 2.0;
542 			double start_angle	= end_angle - M_PI / 2.0  / ((double) bdr_left / (double) bdr_top + 0.5);
543 
544 			if (!add_path_arc(cr,
545 				draw_pos.left() + r_left,
546 				draw_pos.top() + r_left,
547 				r_left,
548 				r_left,
549 				end_angle,
550 				start_angle, true))
551 			{
552 				cairo_move_to(cr, draw_pos.left(), draw_pos.top());
553 			}
554 
555 			if (!add_path_arc(cr,
556 				draw_pos.left() + r_left,
557 				draw_pos.top() + r_left,
558 				r_left - bdr_top + (bdr_top - bdr_left),
559 				r_left - bdr_top,
560 				start_angle,
561 				end_angle, false))
562 			{
563 				cairo_line_to(cr, draw_pos.left() + bdr_left, draw_pos.top() + bdr_top);
564 			}
565 		} else
566 		{
567 			cairo_move_to(cr, draw_pos.left(), draw_pos.top());
568 			cairo_line_to(cr, draw_pos.left() + bdr_left, draw_pos.top() + bdr_top);
569 		}
570 
571 		if(r_right)
572 		{
573 			cairo_line_to(cr, draw_pos.right() - r_right,	draw_pos.top() + bdr_top);
574 
575 			double start_angle	= M_PI * 3.0 / 2.0;
576 			double end_angle	= start_angle + M_PI / 2.0  / ((double) bdr_right / (double) bdr_top + 0.5);
577 
578 			if (!add_path_arc(cr,
579 				draw_pos.right() - r_right,
580 				draw_pos.top() + r_right,
581 				r_right - bdr_top + (bdr_top - bdr_right),
582 				r_right - bdr_top,
583 				start_angle,
584 				end_angle, false))
585 			{
586 				cairo_line_to(cr, draw_pos.right() - bdr_right, draw_pos.top() + bdr_top);
587 			}
588 
589 			if (!add_path_arc(cr,
590 				draw_pos.right() - r_right,
591 				draw_pos.top() + r_right,
592 				r_right,
593 				r_right,
594 				end_angle,
595 				start_angle, true))
596 			{
597 				cairo_line_to(cr, draw_pos.right(), draw_pos.top());
598 			}
599 		} else
600 		{
601 			cairo_line_to(cr, draw_pos.right() - bdr_right,	draw_pos.top() + bdr_top);
602 			cairo_line_to(cr, draw_pos.right(),	draw_pos.top());
603 		}
604 
605 		cairo_fill(cr);
606 	}
607 
608 	// draw left border
609 	if (bdr_left)
610 	{
611 		set_color(cr, borders.left.color);
612 
613 		double r_top	= borders.radius.top_left_x;
614 		double r_bottom	= borders.radius.bottom_left_x;
615 
616 		if(r_top)
617 		{
618 			double start_angle	= M_PI;
619 			double end_angle	= start_angle + M_PI / 2.0  / ((double) bdr_top / (double) bdr_left + 0.5);
620 
621 			if (!add_path_arc(cr,
622 				draw_pos.left() + r_top,
623 				draw_pos.top() + r_top,
624 				r_top - bdr_left,
625 				r_top - bdr_left + (bdr_left - bdr_top),
626 				start_angle,
627 				end_angle, false))
628 			{
629 				cairo_move_to(cr, draw_pos.left() + bdr_left, draw_pos.top() + bdr_top);
630 			}
631 
632 			if (!add_path_arc(cr,
633 				draw_pos.left() + r_top,
634 				draw_pos.top() + r_top,
635 				r_top,
636 				r_top,
637 				end_angle,
638 				start_angle, true))
639 			{
640 				cairo_line_to(cr, draw_pos.left(), draw_pos.top());
641 			}
642 		} else
643 		{
644 			cairo_move_to(cr, draw_pos.left() + bdr_left, draw_pos.top() + bdr_top);
645 			cairo_line_to(cr, draw_pos.left(), draw_pos.top());
646 		}
647 
648 		if(r_bottom)
649 		{
650 			cairo_line_to(cr, draw_pos.left(),	draw_pos.bottom() - r_bottom);
651 
652 			double end_angle	= M_PI;
653 			double start_angle	= end_angle - M_PI / 2.0  / ((double) bdr_bottom / (double) bdr_left + 0.5);
654 
655 			if (!add_path_arc(cr,
656 				draw_pos.left() + r_bottom,
657 				draw_pos.bottom() - r_bottom,
658 				r_bottom,
659 				r_bottom,
660 				end_angle,
661 				start_angle, true))
662 			{
663 				cairo_line_to(cr, draw_pos.left(), draw_pos.bottom());
664 			}
665 
666 			if (!add_path_arc(cr,
667 				draw_pos.left() + r_bottom,
668 				draw_pos.bottom() - r_bottom,
669 				r_bottom - bdr_left,
670 				r_bottom - bdr_left + (bdr_left - bdr_bottom),
671 				start_angle,
672 				end_angle, false))
673 			{
674 				cairo_line_to(cr, draw_pos.left() + bdr_left, draw_pos.bottom() - bdr_bottom);
675 			}
676 		} else
677 		{
678 			cairo_line_to(cr, draw_pos.left(),	draw_pos.bottom());
679 			cairo_line_to(cr, draw_pos.left() + bdr_left,	draw_pos.bottom() - bdr_bottom);
680 		}
681 
682 		cairo_fill(cr);
683 	}
684 	cairo_restore(cr);
685 }
686 
set_clip(const litehtml::position & pos,const litehtml::border_radiuses & bdr_radius,bool valid_x,bool valid_y)687 void cairo_container::set_clip(const litehtml::position& pos, const litehtml::border_radiuses& bdr_radius, bool valid_x, bool valid_y)
688 {
689 	litehtml::position clip_pos = pos;
690 	litehtml::position client_pos;
691 	get_client_rect(client_pos);
692 	if(!valid_x)
693 	{
694 		clip_pos.x		= client_pos.x;
695 		clip_pos.width	= client_pos.width;
696 	}
697 	if(!valid_y)
698 	{
699 		clip_pos.y		= client_pos.y;
700 		clip_pos.height	= client_pos.height;
701 	}
702 	m_clips.emplace_back(clip_pos, bdr_radius);
703 }
704 
del_clip()705 void cairo_container::del_clip()
706 {
707 	if(!m_clips.empty())
708 	{
709 		m_clips.pop_back();
710 	}
711 }
712 
apply_clip(cairo_t * cr)713 void cairo_container::apply_clip( cairo_t* cr )
714 {
715 	for(const auto& clip_box : m_clips)
716 	{
717 		rounded_rectangle(cr, clip_box.box, clip_box.radius);
718 		cairo_clip(cr);
719 	}
720 }
721 
draw_ellipse(cairo_t * cr,int x,int y,int width,int height,const litehtml::web_color & color,double line_width)722 void cairo_container::draw_ellipse( cairo_t* cr, int x, int y, int width, int height, const litehtml::web_color& color, double line_width )
723 {
724 	if(!cr) return;
725 	cairo_save(cr);
726 
727 	apply_clip(cr);
728 
729 	cairo_new_path(cr);
730 
731 	cairo_translate (cr, x + width / 2.0, y + height / 2.0);
732 	cairo_scale (cr, width / 2.0, height / 2.0);
733 	cairo_arc (cr, 0, 0, 1, 0, 2 * M_PI);
734 
735 	set_color(cr, color);
736 	cairo_set_line_width(cr, line_width);
737 	cairo_stroke(cr);
738 
739 	cairo_restore(cr);
740 }
741 
fill_ellipse(cairo_t * cr,int x,int y,int width,int height,const litehtml::web_color & color)742 void cairo_container::fill_ellipse( cairo_t* cr, int x, int y, int width, int height, const litehtml::web_color& color )
743 {
744 	if(!cr) return;
745 	cairo_save(cr);
746 
747 	apply_clip(cr);
748 
749 	cairo_new_path(cr);
750 
751 	cairo_translate (cr, x + width / 2.0, y + height / 2.0);
752 	cairo_scale (cr, width / 2.0, height / 2.0);
753 	cairo_arc (cr, 0, 0, 1, 0, 2 * M_PI);
754 
755 	set_color(cr, color);
756 	cairo_fill(cr);
757 
758 	cairo_restore(cr);
759 }
760 
clear_images()761 void cairo_container::clear_images()
762 {
763 	lock_images_cache();
764 	m_images.clear();
765 	unlock_images_cache();
766 }
767 
get_default_font_name() const768 const litehtml::tchar_t* cairo_container::get_default_font_name() const
769 {
770 	return _t("Times New Roman");
771 }
772 
draw_txdib(cairo_t * cr,CTxDIB * bmp,int x,int y,int cx,int cy)773 void cairo_container::draw_txdib( cairo_t* cr, CTxDIB* bmp, int x, int y, int cx, int cy )
774 {
775 	cairo_save(cr);
776 
777 	cairo_matrix_t flib_m;
778 	cairo_matrix_init(&flib_m, 1, 0, 0, -1, 0, 0);
779 
780 	cairo_surface_t* img = NULL;
781 
782 	CTxDIB rbmp;
783 
784 	if(cx != bmp->getWidth() || cy != bmp->getHeight())
785 	{
786 		bmp->resample(cx, cy, &rbmp);
787 		img = cairo_image_surface_create_for_data((unsigned char*) rbmp.getBits(), CAIRO_FORMAT_ARGB32, rbmp.getWidth(), rbmp.getHeight(), rbmp.getWidth() * 4);
788 		cairo_matrix_translate(&flib_m, 0, -rbmp.getHeight());
789 		cairo_matrix_translate(&flib_m, x, -y);
790 	} else
791 	{
792 		img = cairo_image_surface_create_for_data((unsigned char*) bmp->getBits(), CAIRO_FORMAT_ARGB32, bmp->getWidth(), bmp->getHeight(), bmp->getWidth() * 4);
793 		cairo_matrix_translate(&flib_m, 0, -bmp->getHeight());
794 		cairo_matrix_translate(&flib_m, x, -y);
795 	}
796 
797 	cairo_transform(cr, &flib_m);
798 	cairo_set_source_surface(cr, img, 0, 0);
799 	cairo_paint(cr);
800 
801 	cairo_restore(cr);
802 	cairo_surface_destroy(img);
803 }
804 
rounded_rectangle(cairo_t * cr,const litehtml::position & pos,const litehtml::border_radiuses & radius)805 void cairo_container::rounded_rectangle(cairo_t* cr, const litehtml::position& pos, const litehtml::border_radiuses& radius)
806 {
807 	cairo_new_path(cr);
808 	if(radius.top_left_x)
809 	{
810 		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);
811 	} else
812 	{
813 		cairo_move_to(cr, pos.left(), pos.top());
814 	}
815 
816 	cairo_line_to(cr, pos.right() - radius.top_right_x, pos.top());
817 
818 	if(radius.top_right_x)
819 	{
820 		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);
821 	}
822 
823 	cairo_line_to(cr, pos.right(), pos.bottom() - radius.bottom_right_x);
824 
825 	if(radius.bottom_right_x)
826 	{
827 		cairo_arc(cr, pos.right() - radius.bottom_right_x, pos.bottom() - radius.bottom_right_x, radius.bottom_right_x, 0, M_PI / 2.0);
828 	}
829 
830 	cairo_line_to(cr, pos.left() - radius.bottom_left_x, pos.bottom());
831 
832 	if(radius.bottom_left_x)
833 	{
834 		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);
835 	}
836 }
837 
remove_image(std::wstring & url)838 void cairo_container::remove_image( std::wstring& url )
839 {
840 	lock_images_cache();
841 	images_map::iterator i = m_images.find(url);
842 	if(i != m_images.end())
843 	{
844 		m_images.erase(i);
845 	}
846 	unlock_images_cache();
847 }
848 
add_image(std::wstring & url,image_ptr & img)849 void cairo_container::add_image(std::wstring& url, image_ptr& img)
850 {
851 	lock_images_cache();
852 	images_map::iterator i = m_images.find(url);
853 	if(i != m_images.end())
854 	{
855 		if(img)
856 		{
857 			i->second = img;
858 		} else
859 		{
860 			m_images.erase(i);
861 		}
862 	}
863 	unlock_images_cache();
864 }
865 
lock_images_cache()866 void cairo_container::lock_images_cache()
867 {
868 	EnterCriticalSection(&m_img_sync);
869 }
870 
unlock_images_cache()871 void cairo_container::unlock_images_cache()
872 {
873 	LeaveCriticalSection(&m_img_sync);
874 }
875 
create_element(const litehtml::tchar_t * tag_name,const litehtml::string_map & attributes,const std::shared_ptr<litehtml::document> & doc)876 std::shared_ptr<litehtml::element> cairo_container::create_element(const litehtml::tchar_t* tag_name, const litehtml::string_map& attributes, const std::shared_ptr<litehtml::document>& doc)
877 {
878 	return 0;
879 }
880 
get_media_features(litehtml::media_features & media) const881 void cairo_container::get_media_features(litehtml::media_features& media)  const
882 {
883 	litehtml::position client;
884 	get_client_rect(client);
885 	HDC hdc = GetDC(NULL);
886 
887 	media.type			= litehtml::media_type_screen;
888 	media.width			= client.width;
889 	media.height		= client.height;
890 	media.color			= 8;
891 	media.monochrome	= 0;
892 	media.color_index	= 256;
893 	media.resolution	= GetDeviceCaps(hdc, LOGPIXELSX);
894 	media.device_width	= GetDeviceCaps(hdc, HORZRES);
895 	media.device_height	= GetDeviceCaps(hdc, VERTRES);
896 
897 	ReleaseDC(NULL, hdc);
898 }
899 
get_language(litehtml::tstring & language,litehtml::tstring & culture) const900 void cairo_container::get_language(litehtml::tstring& language, litehtml::tstring & culture) const
901 {
902 	language = _t("en");
903 	culture = _t("");
904 }
905 
make_url_utf8(const char * url,const char * basepath,std::wstring & out)906 void cairo_container::make_url_utf8( const char* url, const char* basepath, std::wstring& out )
907 {
908 	wchar_t* urlW = cairo_font::utf8_to_wchar(url);
909 	wchar_t* basepathW = cairo_font::utf8_to_wchar(basepath);
910 	make_url(urlW, basepathW, out);
911 
912 	if(urlW) delete urlW;
913 	if(basepathW) delete basepathW;
914 }
915 
transform_text(litehtml::tstring & text,litehtml::text_transform tt)916 void cairo_container::transform_text( litehtml::tstring& text, litehtml::text_transform tt )
917 {
918 	if(text.empty()) return;
919 
920 #ifndef LITEHTML_UTF8
921 	switch(tt)
922 	{
923 	case litehtml::text_transform_capitalize:
924 		if(!text.empty())
925 		{
926 			text[0] = (WCHAR) CharUpper((LPWSTR) text[0]);
927 		}
928 		break;
929 	case litehtml::text_transform_uppercase:
930 		for(size_t i = 0; i < text.length(); i++)
931 		{
932 			text[i] = (WCHAR) CharUpper((LPWSTR) text[i]);
933 		}
934 		break;
935 	case litehtml::text_transform_lowercase:
936 		for(size_t i = 0; i < text.length(); i++)
937 		{
938 			text[i] = (WCHAR) CharLower((LPWSTR) text[i]);
939 		}
940 		break;
941 	}
942 #else
943 	LPWSTR txt = cairo_font::utf8_to_wchar(text.c_str());
944 	switch(tt)
945 	{
946 	case litehtml::text_transform_capitalize:
947 		CharUpperBuff(txt, 1);
948 		break;
949 	case litehtml::text_transform_uppercase:
950 		CharUpperBuff(txt, lstrlen(txt));
951 		break;
952 	case litehtml::text_transform_lowercase:
953 		CharLowerBuff(txt, lstrlen(txt));
954 		break;
955 	}
956 	LPSTR txtA = cairo_font::wchar_to_utf8(txt);
957 	text = txtA;
958 	delete txtA;
959 	delete txt;
960 #endif
961 }
962 
link(const std::shared_ptr<litehtml::document> & doc,const litehtml::element::ptr & el)963 void cairo_container::link(const std::shared_ptr<litehtml::document>& doc, const litehtml::element::ptr& el)
964 {
965 }
966 
resolve_color(const litehtml::tstring & color) const967 litehtml::tstring cairo_container::resolve_color(const litehtml::tstring& color) const
968 {
969 	struct custom_color
970 	{
971 		litehtml::tchar_t*	name;
972 		int					color_index;
973 	};
974 
975 	static custom_color colors[] = {
976 		{ _t("ActiveBorder"),          COLOR_ACTIVEBORDER},
977 		{ _t("ActiveCaption"),         COLOR_ACTIVECAPTION},
978 		{ _t("AppWorkspace"),          COLOR_APPWORKSPACE },
979 		{ _t("Background"),            COLOR_BACKGROUND },
980 		{ _t("ButtonFace"),            COLOR_BTNFACE },
981 		{ _t("ButtonHighlight"),       COLOR_BTNHIGHLIGHT },
982 		{ _t("ButtonShadow"),          COLOR_BTNSHADOW },
983 		{ _t("ButtonText"),            COLOR_BTNTEXT },
984 		{ _t("CaptionText"),           COLOR_CAPTIONTEXT },
985         { _t("GrayText"),              COLOR_GRAYTEXT },
986 		{ _t("Highlight"),             COLOR_HIGHLIGHT },
987 		{ _t("HighlightText"),         COLOR_HIGHLIGHTTEXT },
988 		{ _t("InactiveBorder"),        COLOR_INACTIVEBORDER },
989 		{ _t("InactiveCaption"),       COLOR_INACTIVECAPTION },
990 		{ _t("InactiveCaptionText"),   COLOR_INACTIVECAPTIONTEXT },
991 		{ _t("InfoBackground"),        COLOR_INFOBK },
992 		{ _t("InfoText"),              COLOR_INFOTEXT },
993 		{ _t("Menu"),                  COLOR_MENU },
994 		{ _t("MenuText"),              COLOR_MENUTEXT },
995 		{ _t("Scrollbar"),             COLOR_SCROLLBAR },
996 		{ _t("ThreeDDarkShadow"),      COLOR_3DDKSHADOW },
997 		{ _t("ThreeDFace"),            COLOR_3DFACE },
998 		{ _t("ThreeDHighlight"),       COLOR_3DHILIGHT },
999 		{ _t("ThreeDLightShadow"),     COLOR_3DLIGHT },
1000 		{ _t("ThreeDShadow"),          COLOR_3DSHADOW },
1001 		{ _t("Window"),                COLOR_WINDOW },
1002 		{ _t("WindowFrame"),           COLOR_WINDOWFRAME },
1003 		{ _t("WindowText"),            COLOR_WINDOWTEXT }
1004 	};
1005 
1006     if (color == _t("Highlight"))
1007     {
1008         int iii = 0;
1009         iii++;
1010     }
1011 
1012     for (auto& clr : colors)
1013     {
1014         if (!t_strcasecmp(clr.name, color.c_str()))
1015         {
1016             litehtml::tchar_t  str_clr[20];
1017             DWORD rgb_color =  GetSysColor(clr.color_index);
1018 #ifdef LITEHTML_UTF8
1019             StringCchPrintfA(str_clr, 20, "#%02X%02X%02X", GetRValue(rgb_color), GetGValue(rgb_color), GetBValue(rgb_color));
1020 #else
1021             StringCchPrintf(str_clr, 20, L"#%02X%02X%02X", GetRValue(rgb_color), GetGValue(rgb_color), GetBValue(rgb_color));
1022 #endif // LITEHTML_UTF8
1023             return std::move(litehtml::tstring(str_clr));
1024         }
1025     }
1026     return std::move(litehtml::tstring());
1027 }
1028