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