ea3c8f7f33
page: https://en.wikipedia.org/wiki/UTF-8#Invalid_sequences_and_error_handling culprit: ul{list-style-image:url(/w/skins/Vector/resources/common/images/bullet-icon.svg?d4515)} (invalid because svg is not supported)
1029 lines
26 KiB
C++
1029 lines
26 KiB
C++
#include "cairo_container.h"
|
|
#define _USE_MATH_DEFINES
|
|
#include <math.h>
|
|
#include "cairo_font.h"
|
|
#include <strsafe.h>
|
|
|
|
cairo_container::cairo_container(void)
|
|
{
|
|
m_temp_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 2, 2);
|
|
m_temp_cr = cairo_create(m_temp_surface);
|
|
m_font_link = NULL;
|
|
CoCreateInstance(CLSID_CMultiLanguage, NULL, CLSCTX_ALL, IID_IMLangFontLink2, (void**) &m_font_link);
|
|
InitializeCriticalSection(&m_img_sync);
|
|
}
|
|
|
|
cairo_container::~cairo_container(void)
|
|
{
|
|
clear_images();
|
|
if(m_font_link)
|
|
{
|
|
m_font_link->Release();
|
|
}
|
|
cairo_surface_destroy(m_temp_surface);
|
|
cairo_destroy(m_temp_cr);
|
|
DeleteCriticalSection(&m_img_sync);
|
|
}
|
|
|
|
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 )
|
|
{
|
|
std::wstring fnt_name = L"sans-serif";
|
|
|
|
litehtml::string_vector fonts;
|
|
litehtml::split_string(faceName, fonts, _t(","));
|
|
if(!fonts.empty())
|
|
{
|
|
litehtml::trim(fonts[0]);
|
|
#ifdef LITEHTML_UTF8
|
|
wchar_t* f = cairo_font::utf8_to_wchar(fonts[0].c_str());
|
|
fnt_name = f;
|
|
delete f;
|
|
#else
|
|
fnt_name = fonts[0];
|
|
if (fnt_name.front() == L'"' || fnt_name.front() == L'\'')
|
|
{
|
|
fnt_name.erase(0, 1);
|
|
}
|
|
if (fnt_name.back() == L'"' || fnt_name.back() == L'\'')
|
|
{
|
|
fnt_name.erase(fnt_name.length() - 1, 1);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
cairo_font* fnt = new cairo_font( m_font_link,
|
|
fnt_name.c_str(),
|
|
size,
|
|
weight,
|
|
(italic == litehtml::fontStyleItalic) ? TRUE : FALSE,
|
|
(decoration & litehtml::font_decoration_linethrough) ? TRUE : FALSE,
|
|
(decoration & litehtml::font_decoration_underline) ? TRUE : FALSE);
|
|
|
|
cairo_save(m_temp_cr);
|
|
fnt->load_metrics(m_temp_cr);
|
|
|
|
if(fm)
|
|
{
|
|
fm->ascent = fnt->metrics().ascent;
|
|
fm->descent = fnt->metrics().descent;
|
|
fm->height = fnt->metrics().height;
|
|
fm->x_height = fnt->metrics().x_height;
|
|
if(italic == litehtml::fontStyleItalic || decoration)
|
|
{
|
|
fm->draw_spaces = true;
|
|
} else
|
|
{
|
|
fm->draw_spaces = false;
|
|
}
|
|
}
|
|
|
|
cairo_restore(m_temp_cr);
|
|
|
|
return (litehtml::uint_ptr) fnt;
|
|
}
|
|
|
|
void cairo_container::delete_font( litehtml::uint_ptr hFont )
|
|
{
|
|
cairo_font* fnt = (cairo_font*) hFont;
|
|
if(fnt)
|
|
{
|
|
delete fnt;
|
|
}
|
|
}
|
|
|
|
int cairo_container::text_width( const litehtml::tchar_t* text, litehtml::uint_ptr hFont )
|
|
{
|
|
cairo_font* fnt = (cairo_font*) hFont;
|
|
|
|
cairo_save(m_temp_cr);
|
|
int ret = fnt->text_width(m_temp_cr, text);
|
|
cairo_restore(m_temp_cr);
|
|
return ret;
|
|
}
|
|
|
|
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 )
|
|
{
|
|
if(hFont)
|
|
{
|
|
cairo_font* fnt = (cairo_font*) hFont;
|
|
cairo_t* cr = (cairo_t*) hdc;
|
|
cairo_save(cr);
|
|
|
|
apply_clip(cr);
|
|
|
|
int x = pos.left();
|
|
int y = pos.bottom() - fnt->metrics().descent;
|
|
|
|
set_color(cr, color);
|
|
fnt->show_text(cr, x, y, text);
|
|
|
|
cairo_restore(cr);
|
|
}
|
|
}
|
|
|
|
int cairo_container::pt_to_px( int pt ) const
|
|
{
|
|
HDC dc = GetDC(NULL);
|
|
int ret = MulDiv(pt, GetDeviceCaps(dc, LOGPIXELSY), 72);
|
|
ReleaseDC(NULL, dc);
|
|
return ret;
|
|
}
|
|
|
|
int cairo_container::get_default_font_size() const
|
|
{
|
|
return 16;
|
|
}
|
|
|
|
void cairo_container::draw_list_marker( litehtml::uint_ptr hdc, const litehtml::list_marker& marker )
|
|
{
|
|
if(!marker.image.empty())
|
|
{
|
|
std::wstring url;
|
|
t_make_url(marker.image.c_str(), marker.baseurl, url);
|
|
|
|
lock_images_cache();
|
|
images_map::iterator img_i = m_images.find(url.c_str());
|
|
if(img_i != m_images.end())
|
|
{
|
|
if(img_i->second)
|
|
{
|
|
draw_txdib((cairo_t*)hdc, img_i->second.get(), marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height);
|
|
unlock_images_cache();
|
|
return;
|
|
}
|
|
}
|
|
unlock_images_cache();
|
|
}
|
|
|
|
switch(marker.marker_type)
|
|
{
|
|
case litehtml::list_style_type_circle:
|
|
{
|
|
draw_ellipse((cairo_t*) hdc, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height, marker.color, 0.5);
|
|
}
|
|
break;
|
|
case litehtml::list_style_type_disc:
|
|
{
|
|
fill_ellipse((cairo_t*) hdc, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height, marker.color);
|
|
}
|
|
break;
|
|
case litehtml::list_style_type_square:
|
|
if(hdc)
|
|
{
|
|
cairo_t* cr = (cairo_t*) hdc;
|
|
cairo_save(cr);
|
|
|
|
cairo_new_path(cr);
|
|
cairo_rectangle(cr, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height);
|
|
|
|
set_color(cr, marker.color);
|
|
cairo_fill(cr);
|
|
cairo_restore(cr);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void cairo_container::load_image( const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, bool redraw_on_ready )
|
|
{
|
|
std::wstring url;
|
|
t_make_url(src, baseurl, url);
|
|
lock_images_cache();
|
|
if(m_images.find(url.c_str()) == m_images.end())
|
|
{
|
|
unlock_images_cache();
|
|
image_ptr img = get_image(url.c_str(), redraw_on_ready);
|
|
lock_images_cache();
|
|
m_images[url] = img;
|
|
unlock_images_cache();
|
|
} else
|
|
{
|
|
unlock_images_cache();
|
|
}
|
|
|
|
}
|
|
|
|
void cairo_container::get_image_size( const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, litehtml::size& sz )
|
|
{
|
|
std::wstring url;
|
|
t_make_url(src, baseurl, url);
|
|
|
|
sz.width = 0;
|
|
sz.height = 0;
|
|
|
|
lock_images_cache();
|
|
images_map::iterator img = m_images.find(url.c_str());
|
|
if(img != m_images.end())
|
|
{
|
|
if(img->second)
|
|
{
|
|
sz.width = img->second->getWidth();
|
|
sz.height = img->second->getHeight();
|
|
}
|
|
}
|
|
unlock_images_cache();
|
|
}
|
|
|
|
void cairo_container::draw_image( litehtml::uint_ptr hdc, const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, const litehtml::position& pos )
|
|
{
|
|
cairo_t* cr = (cairo_t*) hdc;
|
|
cairo_save(cr);
|
|
apply_clip(cr);
|
|
|
|
std::wstring url;
|
|
t_make_url(src, baseurl, url);
|
|
lock_images_cache();
|
|
images_map::iterator img = m_images.find(url.c_str());
|
|
if(img != m_images.end())
|
|
{
|
|
if(img->second)
|
|
{
|
|
draw_txdib(cr, img->second.get(), pos.x, pos.y, pos.width, pos.height);
|
|
}
|
|
}
|
|
unlock_images_cache();
|
|
cairo_restore(cr);
|
|
}
|
|
|
|
void cairo_container::draw_background( litehtml::uint_ptr hdc, const litehtml::background_paint& bg )
|
|
{
|
|
cairo_t* cr = (cairo_t*) hdc;
|
|
cairo_save(cr);
|
|
apply_clip(cr);
|
|
|
|
rounded_rectangle(cr, bg.border_box, bg.border_radius);
|
|
cairo_clip(cr);
|
|
|
|
cairo_rectangle(cr, bg.clip_box.x, bg.clip_box.y, bg.clip_box.width, bg.clip_box.height);
|
|
cairo_clip(cr);
|
|
|
|
if(bg.color.alpha)
|
|
{
|
|
set_color(cr, bg.color);
|
|
cairo_paint(cr);
|
|
}
|
|
|
|
std::wstring url;
|
|
t_make_url(bg.image.c_str(), bg.baseurl.c_str(), url);
|
|
|
|
lock_images_cache();
|
|
images_map::iterator img_i = m_images.find(url.c_str());
|
|
if(img_i != m_images.end() && img_i->second)
|
|
{
|
|
image_ptr bgbmp = img_i->second;
|
|
|
|
image_ptr new_img;
|
|
if(bg.image_size.width != bgbmp->getWidth() || bg.image_size.height != bgbmp->getHeight())
|
|
{
|
|
new_img = image_ptr(new CTxDIB);
|
|
bgbmp->resample(bg.image_size.width, bg.image_size.height, new_img.get());
|
|
bgbmp = new_img;
|
|
}
|
|
|
|
|
|
cairo_surface_t* img = cairo_image_surface_create_for_data((unsigned char*) bgbmp->getBits(), CAIRO_FORMAT_ARGB32, bgbmp->getWidth(), bgbmp->getHeight(), bgbmp->getWidth() * 4);
|
|
cairo_pattern_t *pattern = cairo_pattern_create_for_surface(img);
|
|
cairo_matrix_t flib_m;
|
|
cairo_matrix_init(&flib_m, 1, 0, 0, -1, 0, 0);
|
|
cairo_matrix_translate(&flib_m, -bg.position_x, -bg.position_y);
|
|
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
|
|
cairo_pattern_set_matrix (pattern, &flib_m);
|
|
|
|
switch(bg.repeat)
|
|
{
|
|
case litehtml::background_repeat_no_repeat:
|
|
draw_txdib(cr, bgbmp.get(), bg.position_x, bg.position_y, bgbmp->getWidth(), bgbmp->getHeight());
|
|
break;
|
|
|
|
case litehtml::background_repeat_repeat_x:
|
|
cairo_set_source(cr, pattern);
|
|
cairo_rectangle(cr, bg.clip_box.left(), bg.position_y, bg.clip_box.width, bgbmp->getHeight());
|
|
cairo_fill(cr);
|
|
break;
|
|
|
|
case litehtml::background_repeat_repeat_y:
|
|
cairo_set_source(cr, pattern);
|
|
cairo_rectangle(cr, bg.position_x, bg.clip_box.top(), bgbmp->getWidth(), bg.clip_box.height);
|
|
cairo_fill(cr);
|
|
break;
|
|
|
|
case litehtml::background_repeat_repeat:
|
|
cairo_set_source(cr, pattern);
|
|
cairo_rectangle(cr, bg.clip_box.left(), bg.clip_box.top(), bg.clip_box.width, bg.clip_box.height);
|
|
cairo_fill(cr);
|
|
break;
|
|
}
|
|
|
|
cairo_pattern_destroy(pattern);
|
|
cairo_surface_destroy(img);
|
|
}
|
|
unlock_images_cache();
|
|
cairo_restore(cr);
|
|
}
|
|
|
|
bool cairo_container::add_path_arc(cairo_t* cr, double x, double y, double rx, double ry, double a1, double a2, bool neg)
|
|
{
|
|
if(rx > 0 && ry > 0)
|
|
{
|
|
cairo_save(cr);
|
|
|
|
cairo_translate(cr, x, y);
|
|
cairo_scale(cr, 1, ry / rx);
|
|
cairo_translate(cr, -x, -y);
|
|
|
|
if(neg)
|
|
{
|
|
cairo_arc_negative(cr, x, y, rx, a1, a2);
|
|
} else
|
|
{
|
|
cairo_arc(cr, x, y, rx, a1, a2);
|
|
}
|
|
|
|
cairo_restore(cr);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void cairo_container::draw_borders( litehtml::uint_ptr hdc, const litehtml::borders& borders, const litehtml::position& draw_pos, bool root )
|
|
{
|
|
cairo_t* cr = (cairo_t*) hdc;
|
|
cairo_save(cr);
|
|
apply_clip(cr);
|
|
|
|
cairo_new_path(cr);
|
|
|
|
int bdr_top = 0;
|
|
int bdr_bottom = 0;
|
|
int bdr_left = 0;
|
|
int bdr_right = 0;
|
|
|
|
if(borders.top.width != 0 && borders.top.style > litehtml::border_style_hidden)
|
|
{
|
|
bdr_top = (int) borders.top.width;
|
|
}
|
|
if(borders.bottom.width != 0 && borders.bottom.style > litehtml::border_style_hidden)
|
|
{
|
|
bdr_bottom = (int) borders.bottom.width;
|
|
}
|
|
if(borders.left.width != 0 && borders.left.style > litehtml::border_style_hidden)
|
|
{
|
|
bdr_left = (int) borders.left.width;
|
|
}
|
|
if(borders.right.width != 0 && borders.right.style > litehtml::border_style_hidden)
|
|
{
|
|
bdr_right = (int) borders.right.width;
|
|
}
|
|
|
|
// draw right border
|
|
if (bdr_right)
|
|
{
|
|
set_color(cr, borders.right.color);
|
|
|
|
double r_top = (double) borders.radius.top_right_x;
|
|
double r_bottom = (double) borders.radius.bottom_right_x;
|
|
|
|
if(r_top)
|
|
{
|
|
double end_angle = 2.0 * M_PI;
|
|
double start_angle = end_angle - M_PI / 2.0 / ((double) bdr_top / (double) bdr_right + 0.5);
|
|
|
|
if (!add_path_arc(cr,
|
|
draw_pos.right() - r_top,
|
|
draw_pos.top() + r_top,
|
|
r_top - bdr_right,
|
|
r_top - bdr_right + (bdr_right - bdr_top),
|
|
end_angle,
|
|
start_angle, true))
|
|
{
|
|
cairo_move_to(cr, draw_pos.right() - bdr_right, draw_pos.top() + bdr_top);
|
|
}
|
|
|
|
if (!add_path_arc(cr,
|
|
draw_pos.right() - r_top,
|
|
draw_pos.top() + r_top,
|
|
r_top,
|
|
r_top,
|
|
start_angle,
|
|
end_angle, false))
|
|
{
|
|
cairo_line_to(cr, draw_pos.right(), draw_pos.top());
|
|
}
|
|
} else
|
|
{
|
|
cairo_move_to(cr, draw_pos.right() - bdr_right, draw_pos.top() + bdr_top);
|
|
cairo_line_to(cr, draw_pos.right(), draw_pos.top());
|
|
}
|
|
|
|
if(r_bottom)
|
|
{
|
|
cairo_line_to(cr, draw_pos.right(), draw_pos.bottom() - r_bottom);
|
|
|
|
double start_angle = 0;
|
|
double end_angle = start_angle + M_PI / 2.0 / ((double) bdr_bottom / (double) bdr_right + 0.5);
|
|
|
|
if (!add_path_arc(cr,
|
|
draw_pos.right() - r_bottom,
|
|
draw_pos.bottom() - r_bottom,
|
|
r_bottom,
|
|
r_bottom,
|
|
start_angle,
|
|
end_angle, false))
|
|
{
|
|
cairo_line_to(cr, draw_pos.right(), draw_pos.bottom());
|
|
}
|
|
|
|
if (!add_path_arc(cr,
|
|
draw_pos.right() - r_bottom,
|
|
draw_pos.bottom() - r_bottom,
|
|
r_bottom - bdr_right,
|
|
r_bottom - bdr_right + (bdr_right - bdr_bottom),
|
|
end_angle,
|
|
start_angle, true))
|
|
{
|
|
cairo_line_to(cr, draw_pos.right() - bdr_right, draw_pos.bottom() - bdr_bottom);
|
|
}
|
|
} else
|
|
{
|
|
cairo_line_to(cr, draw_pos.right(), draw_pos.bottom());
|
|
cairo_line_to(cr, draw_pos.right() - bdr_right, draw_pos.bottom() - bdr_bottom);
|
|
}
|
|
|
|
cairo_fill(cr);
|
|
}
|
|
|
|
// draw bottom border
|
|
if(bdr_bottom)
|
|
{
|
|
set_color(cr, borders.bottom.color);
|
|
|
|
double r_left = borders.radius.bottom_left_x;
|
|
double r_right = borders.radius.bottom_right_x;
|
|
|
|
if(r_left)
|
|
{
|
|
double start_angle = M_PI / 2.0;
|
|
double end_angle = start_angle + M_PI / 2.0 / ((double) bdr_left / (double) bdr_bottom + 0.5);
|
|
|
|
if (!add_path_arc(cr,
|
|
draw_pos.left() + r_left,
|
|
draw_pos.bottom() - r_left,
|
|
r_left - bdr_bottom + (bdr_bottom - bdr_left),
|
|
r_left - bdr_bottom,
|
|
start_angle,
|
|
end_angle, false))
|
|
{
|
|
cairo_move_to(cr, draw_pos.left() + bdr_left, draw_pos.bottom() - bdr_bottom);
|
|
}
|
|
|
|
if (!add_path_arc(cr,
|
|
draw_pos.left() + r_left,
|
|
draw_pos.bottom() - r_left,
|
|
r_left,
|
|
r_left,
|
|
end_angle,
|
|
start_angle, true))
|
|
{
|
|
cairo_line_to(cr, draw_pos.left(), draw_pos.bottom());
|
|
}
|
|
} else
|
|
{
|
|
cairo_move_to(cr, draw_pos.left(), draw_pos.bottom());
|
|
cairo_line_to(cr, draw_pos.left() + bdr_left, draw_pos.bottom() - bdr_bottom);
|
|
}
|
|
|
|
if(r_right)
|
|
{
|
|
cairo_line_to(cr, draw_pos.right() - r_right, draw_pos.bottom());
|
|
|
|
double end_angle = M_PI / 2.0;
|
|
double start_angle = end_angle - M_PI / 2.0 / ((double) bdr_right / (double) bdr_bottom + 0.5);
|
|
|
|
if (!add_path_arc(cr,
|
|
draw_pos.right() - r_right,
|
|
draw_pos.bottom() - r_right,
|
|
r_right,
|
|
r_right,
|
|
end_angle,
|
|
start_angle, true))
|
|
{
|
|
cairo_line_to(cr, draw_pos.right(), draw_pos.bottom());
|
|
}
|
|
|
|
if (!add_path_arc(cr,
|
|
draw_pos.right() - r_right,
|
|
draw_pos.bottom() - r_right,
|
|
r_right - bdr_bottom + (bdr_bottom - bdr_right),
|
|
r_right - bdr_bottom,
|
|
start_angle,
|
|
end_angle, false))
|
|
{
|
|
cairo_line_to(cr, draw_pos.right() - bdr_right, draw_pos.bottom() - bdr_bottom);
|
|
}
|
|
} else
|
|
{
|
|
cairo_line_to(cr, draw_pos.right() - bdr_right, draw_pos.bottom() - bdr_bottom);
|
|
cairo_line_to(cr, draw_pos.right(), draw_pos.bottom());
|
|
}
|
|
|
|
cairo_fill(cr);
|
|
}
|
|
|
|
// draw top border
|
|
if(bdr_top)
|
|
{
|
|
set_color(cr, borders.top.color);
|
|
|
|
double r_left = borders.radius.top_left_x;
|
|
double r_right = borders.radius.top_right_x;
|
|
|
|
if(r_left)
|
|
{
|
|
double end_angle = M_PI * 3.0 / 2.0;
|
|
double start_angle = end_angle - M_PI / 2.0 / ((double) bdr_left / (double) bdr_top + 0.5);
|
|
|
|
if (!add_path_arc(cr,
|
|
draw_pos.left() + r_left,
|
|
draw_pos.top() + r_left,
|
|
r_left,
|
|
r_left,
|
|
end_angle,
|
|
start_angle, true))
|
|
{
|
|
cairo_move_to(cr, draw_pos.left(), draw_pos.top());
|
|
}
|
|
|
|
if (!add_path_arc(cr,
|
|
draw_pos.left() + r_left,
|
|
draw_pos.top() + r_left,
|
|
r_left - bdr_top + (bdr_top - bdr_left),
|
|
r_left - bdr_top,
|
|
start_angle,
|
|
end_angle, false))
|
|
{
|
|
cairo_line_to(cr, draw_pos.left() + bdr_left, draw_pos.top() + bdr_top);
|
|
}
|
|
} else
|
|
{
|
|
cairo_move_to(cr, draw_pos.left(), draw_pos.top());
|
|
cairo_line_to(cr, draw_pos.left() + bdr_left, draw_pos.top() + bdr_top);
|
|
}
|
|
|
|
if(r_right)
|
|
{
|
|
cairo_line_to(cr, draw_pos.right() - r_right, draw_pos.top() + bdr_top);
|
|
|
|
double start_angle = M_PI * 3.0 / 2.0;
|
|
double end_angle = start_angle + M_PI / 2.0 / ((double) bdr_right / (double) bdr_top + 0.5);
|
|
|
|
if (!add_path_arc(cr,
|
|
draw_pos.right() - r_right,
|
|
draw_pos.top() + r_right,
|
|
r_right - bdr_top + (bdr_top - bdr_right),
|
|
r_right - bdr_top,
|
|
start_angle,
|
|
end_angle, false))
|
|
{
|
|
cairo_line_to(cr, draw_pos.right() - bdr_right, draw_pos.top() + bdr_top);
|
|
}
|
|
|
|
if (!add_path_arc(cr,
|
|
draw_pos.right() - r_right,
|
|
draw_pos.top() + r_right,
|
|
r_right,
|
|
r_right,
|
|
end_angle,
|
|
start_angle, true))
|
|
{
|
|
cairo_line_to(cr, draw_pos.right(), draw_pos.top());
|
|
}
|
|
} else
|
|
{
|
|
cairo_line_to(cr, draw_pos.right() - bdr_right, draw_pos.top() + bdr_top);
|
|
cairo_line_to(cr, draw_pos.right(), draw_pos.top());
|
|
}
|
|
|
|
cairo_fill(cr);
|
|
}
|
|
|
|
// draw left border
|
|
if (bdr_left)
|
|
{
|
|
set_color(cr, borders.left.color);
|
|
|
|
double r_top = borders.radius.top_left_x;
|
|
double r_bottom = borders.radius.bottom_left_x;
|
|
|
|
if(r_top)
|
|
{
|
|
double start_angle = M_PI;
|
|
double end_angle = start_angle + M_PI / 2.0 / ((double) bdr_top / (double) bdr_left + 0.5);
|
|
|
|
if (!add_path_arc(cr,
|
|
draw_pos.left() + r_top,
|
|
draw_pos.top() + r_top,
|
|
r_top - bdr_left,
|
|
r_top - bdr_left + (bdr_left - bdr_top),
|
|
start_angle,
|
|
end_angle, false))
|
|
{
|
|
cairo_move_to(cr, draw_pos.left() + bdr_left, draw_pos.top() + bdr_top);
|
|
}
|
|
|
|
if (!add_path_arc(cr,
|
|
draw_pos.left() + r_top,
|
|
draw_pos.top() + r_top,
|
|
r_top,
|
|
r_top,
|
|
end_angle,
|
|
start_angle, true))
|
|
{
|
|
cairo_line_to(cr, draw_pos.left(), draw_pos.top());
|
|
}
|
|
} else
|
|
{
|
|
cairo_move_to(cr, draw_pos.left() + bdr_left, draw_pos.top() + bdr_top);
|
|
cairo_line_to(cr, draw_pos.left(), draw_pos.top());
|
|
}
|
|
|
|
if(r_bottom)
|
|
{
|
|
cairo_line_to(cr, draw_pos.left(), draw_pos.bottom() - r_bottom);
|
|
|
|
double end_angle = M_PI;
|
|
double start_angle = end_angle - M_PI / 2.0 / ((double) bdr_bottom / (double) bdr_left + 0.5);
|
|
|
|
if (!add_path_arc(cr,
|
|
draw_pos.left() + r_bottom,
|
|
draw_pos.bottom() - r_bottom,
|
|
r_bottom,
|
|
r_bottom,
|
|
end_angle,
|
|
start_angle, true))
|
|
{
|
|
cairo_line_to(cr, draw_pos.left(), draw_pos.bottom());
|
|
}
|
|
|
|
if (!add_path_arc(cr,
|
|
draw_pos.left() + r_bottom,
|
|
draw_pos.bottom() - r_bottom,
|
|
r_bottom - bdr_left,
|
|
r_bottom - bdr_left + (bdr_left - bdr_bottom),
|
|
start_angle,
|
|
end_angle, false))
|
|
{
|
|
cairo_line_to(cr, draw_pos.left() + bdr_left, draw_pos.bottom() - bdr_bottom);
|
|
}
|
|
} else
|
|
{
|
|
cairo_line_to(cr, draw_pos.left(), draw_pos.bottom());
|
|
cairo_line_to(cr, draw_pos.left() + bdr_left, draw_pos.bottom() - bdr_bottom);
|
|
}
|
|
|
|
cairo_fill(cr);
|
|
}
|
|
cairo_restore(cr);
|
|
}
|
|
|
|
void cairo_container::set_clip(const litehtml::position& pos, const litehtml::border_radiuses& bdr_radius, bool valid_x, bool valid_y)
|
|
{
|
|
litehtml::position clip_pos = pos;
|
|
litehtml::position client_pos;
|
|
get_client_rect(client_pos);
|
|
if(!valid_x)
|
|
{
|
|
clip_pos.x = client_pos.x;
|
|
clip_pos.width = client_pos.width;
|
|
}
|
|
if(!valid_y)
|
|
{
|
|
clip_pos.y = client_pos.y;
|
|
clip_pos.height = client_pos.height;
|
|
}
|
|
m_clips.emplace_back(clip_pos, bdr_radius);
|
|
}
|
|
|
|
void cairo_container::del_clip()
|
|
{
|
|
if(!m_clips.empty())
|
|
{
|
|
m_clips.pop_back();
|
|
}
|
|
}
|
|
|
|
void cairo_container::apply_clip( cairo_t* cr )
|
|
{
|
|
for(const auto& clip_box : m_clips)
|
|
{
|
|
rounded_rectangle(cr, clip_box.box, clip_box.radius);
|
|
cairo_clip(cr);
|
|
}
|
|
}
|
|
|
|
void cairo_container::draw_ellipse( cairo_t* cr, int x, int y, int width, int height, const litehtml::web_color& color, double line_width )
|
|
{
|
|
if(!cr) return;
|
|
cairo_save(cr);
|
|
|
|
apply_clip(cr);
|
|
|
|
cairo_new_path(cr);
|
|
|
|
cairo_translate (cr, x + width / 2.0, y + height / 2.0);
|
|
cairo_scale (cr, width / 2.0, height / 2.0);
|
|
cairo_arc (cr, 0, 0, 1, 0, 2 * M_PI);
|
|
|
|
set_color(cr, color);
|
|
cairo_set_line_width(cr, line_width);
|
|
cairo_stroke(cr);
|
|
|
|
cairo_restore(cr);
|
|
}
|
|
|
|
void cairo_container::fill_ellipse( cairo_t* cr, int x, int y, int width, int height, const litehtml::web_color& color )
|
|
{
|
|
if(!cr) return;
|
|
cairo_save(cr);
|
|
|
|
apply_clip(cr);
|
|
|
|
cairo_new_path(cr);
|
|
|
|
cairo_translate (cr, x + width / 2.0, y + height / 2.0);
|
|
cairo_scale (cr, width / 2.0, height / 2.0);
|
|
cairo_arc (cr, 0, 0, 1, 0, 2 * M_PI);
|
|
|
|
set_color(cr, color);
|
|
cairo_fill(cr);
|
|
|
|
cairo_restore(cr);
|
|
}
|
|
|
|
void cairo_container::clear_images()
|
|
{
|
|
lock_images_cache();
|
|
m_images.clear();
|
|
unlock_images_cache();
|
|
}
|
|
|
|
const litehtml::tchar_t* cairo_container::get_default_font_name() const
|
|
{
|
|
return _t("Times New Roman");
|
|
}
|
|
|
|
void cairo_container::draw_txdib( cairo_t* cr, CTxDIB* bmp, int x, int y, int cx, int cy )
|
|
{
|
|
cairo_save(cr);
|
|
|
|
cairo_matrix_t flib_m;
|
|
cairo_matrix_init(&flib_m, 1, 0, 0, -1, 0, 0);
|
|
|
|
cairo_surface_t* img = NULL;
|
|
|
|
CTxDIB rbmp;
|
|
|
|
if(cx != bmp->getWidth() || cy != bmp->getHeight())
|
|
{
|
|
bmp->resample(cx, cy, &rbmp);
|
|
img = cairo_image_surface_create_for_data((unsigned char*) rbmp.getBits(), CAIRO_FORMAT_ARGB32, rbmp.getWidth(), rbmp.getHeight(), rbmp.getWidth() * 4);
|
|
cairo_matrix_translate(&flib_m, 0, -rbmp.getHeight());
|
|
cairo_matrix_translate(&flib_m, x, -y);
|
|
} else
|
|
{
|
|
img = cairo_image_surface_create_for_data((unsigned char*) bmp->getBits(), CAIRO_FORMAT_ARGB32, bmp->getWidth(), bmp->getHeight(), bmp->getWidth() * 4);
|
|
cairo_matrix_translate(&flib_m, 0, -bmp->getHeight());
|
|
cairo_matrix_translate(&flib_m, x, -y);
|
|
}
|
|
|
|
cairo_transform(cr, &flib_m);
|
|
cairo_set_source_surface(cr, img, 0, 0);
|
|
cairo_paint(cr);
|
|
|
|
cairo_restore(cr);
|
|
cairo_surface_destroy(img);
|
|
}
|
|
|
|
void cairo_container::rounded_rectangle(cairo_t* cr, const litehtml::position& pos, const litehtml::border_radiuses& radius)
|
|
{
|
|
cairo_new_path(cr);
|
|
if(radius.top_left_x)
|
|
{
|
|
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);
|
|
} else
|
|
{
|
|
cairo_move_to(cr, pos.left(), pos.top());
|
|
}
|
|
|
|
cairo_line_to(cr, pos.right() - radius.top_right_x, pos.top());
|
|
|
|
if(radius.top_right_x)
|
|
{
|
|
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);
|
|
}
|
|
|
|
cairo_line_to(cr, pos.right(), pos.bottom() - radius.bottom_right_x);
|
|
|
|
if(radius.bottom_right_x)
|
|
{
|
|
cairo_arc(cr, pos.right() - radius.bottom_right_x, pos.bottom() - radius.bottom_right_x, radius.bottom_right_x, 0, M_PI / 2.0);
|
|
}
|
|
|
|
cairo_line_to(cr, pos.left() - radius.bottom_left_x, pos.bottom());
|
|
|
|
if(radius.bottom_left_x)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
|
|
void cairo_container::remove_image( std::wstring& url )
|
|
{
|
|
lock_images_cache();
|
|
images_map::iterator i = m_images.find(url);
|
|
if(i != m_images.end())
|
|
{
|
|
m_images.erase(i);
|
|
}
|
|
unlock_images_cache();
|
|
}
|
|
|
|
void cairo_container::add_image(std::wstring& url, image_ptr& img)
|
|
{
|
|
lock_images_cache();
|
|
images_map::iterator i = m_images.find(url);
|
|
if(i != m_images.end())
|
|
{
|
|
if(img)
|
|
{
|
|
i->second = img;
|
|
} else
|
|
{
|
|
m_images.erase(i);
|
|
}
|
|
}
|
|
unlock_images_cache();
|
|
}
|
|
|
|
void cairo_container::lock_images_cache()
|
|
{
|
|
EnterCriticalSection(&m_img_sync);
|
|
}
|
|
|
|
void cairo_container::unlock_images_cache()
|
|
{
|
|
LeaveCriticalSection(&m_img_sync);
|
|
}
|
|
|
|
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)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void cairo_container::get_media_features(litehtml::media_features& media) const
|
|
{
|
|
litehtml::position client;
|
|
get_client_rect(client);
|
|
HDC hdc = GetDC(NULL);
|
|
|
|
media.type = litehtml::media_type_screen;
|
|
media.width = client.width;
|
|
media.height = client.height;
|
|
media.color = 8;
|
|
media.monochrome = 0;
|
|
media.color_index = 256;
|
|
media.resolution = GetDeviceCaps(hdc, LOGPIXELSX);
|
|
media.device_width = GetDeviceCaps(hdc, HORZRES);
|
|
media.device_height = GetDeviceCaps(hdc, VERTRES);
|
|
|
|
ReleaseDC(NULL, hdc);
|
|
}
|
|
|
|
void cairo_container::get_language(litehtml::tstring& language, litehtml::tstring & culture) const
|
|
{
|
|
language = _t("en");
|
|
culture = _t("");
|
|
}
|
|
|
|
void cairo_container::make_url_utf8( const char* url, const char* basepath, std::wstring& out )
|
|
{
|
|
wchar_t* urlW = cairo_font::utf8_to_wchar(url);
|
|
wchar_t* basepathW = cairo_font::utf8_to_wchar(basepath);
|
|
make_url(urlW, basepathW, out);
|
|
|
|
if(urlW) delete urlW;
|
|
if(basepathW) delete basepathW;
|
|
}
|
|
|
|
void cairo_container::transform_text( litehtml::tstring& text, litehtml::text_transform tt )
|
|
{
|
|
if(text.empty()) return;
|
|
|
|
#ifndef LITEHTML_UTF8
|
|
switch(tt)
|
|
{
|
|
case litehtml::text_transform_capitalize:
|
|
if(!text.empty())
|
|
{
|
|
text[0] = (WCHAR) CharUpper((LPWSTR) text[0]);
|
|
}
|
|
break;
|
|
case litehtml::text_transform_uppercase:
|
|
for(size_t i = 0; i < text.length(); i++)
|
|
{
|
|
text[i] = (WCHAR) CharUpper((LPWSTR) text[i]);
|
|
}
|
|
break;
|
|
case litehtml::text_transform_lowercase:
|
|
for(size_t i = 0; i < text.length(); i++)
|
|
{
|
|
text[i] = (WCHAR) CharLower((LPWSTR) text[i]);
|
|
}
|
|
break;
|
|
}
|
|
#else
|
|
LPWSTR txt = cairo_font::utf8_to_wchar(text.c_str());
|
|
switch(tt)
|
|
{
|
|
case litehtml::text_transform_capitalize:
|
|
CharUpperBuff(txt, 1);
|
|
break;
|
|
case litehtml::text_transform_uppercase:
|
|
CharUpperBuff(txt, lstrlen(txt));
|
|
break;
|
|
case litehtml::text_transform_lowercase:
|
|
CharLowerBuff(txt, lstrlen(txt));
|
|
break;
|
|
}
|
|
LPSTR txtA = cairo_font::wchar_to_utf8(txt);
|
|
text = txtA;
|
|
delete txtA;
|
|
delete txt;
|
|
#endif
|
|
}
|
|
|
|
void cairo_container::link(const std::shared_ptr<litehtml::document>& doc, const litehtml::element::ptr& el)
|
|
{
|
|
}
|
|
|
|
litehtml::tstring cairo_container::resolve_color(const litehtml::tstring& color) const
|
|
{
|
|
struct custom_color
|
|
{
|
|
litehtml::tchar_t* name;
|
|
int color_index;
|
|
};
|
|
|
|
static custom_color colors[] = {
|
|
{ _t("ActiveBorder"), COLOR_ACTIVEBORDER},
|
|
{ _t("ActiveCaption"), COLOR_ACTIVECAPTION},
|
|
{ _t("AppWorkspace"), COLOR_APPWORKSPACE },
|
|
{ _t("Background"), COLOR_BACKGROUND },
|
|
{ _t("ButtonFace"), COLOR_BTNFACE },
|
|
{ _t("ButtonHighlight"), COLOR_BTNHIGHLIGHT },
|
|
{ _t("ButtonShadow"), COLOR_BTNSHADOW },
|
|
{ _t("ButtonText"), COLOR_BTNTEXT },
|
|
{ _t("CaptionText"), COLOR_CAPTIONTEXT },
|
|
{ _t("GrayText"), COLOR_GRAYTEXT },
|
|
{ _t("Highlight"), COLOR_HIGHLIGHT },
|
|
{ _t("HighlightText"), COLOR_HIGHLIGHTTEXT },
|
|
{ _t("InactiveBorder"), COLOR_INACTIVEBORDER },
|
|
{ _t("InactiveCaption"), COLOR_INACTIVECAPTION },
|
|
{ _t("InactiveCaptionText"), COLOR_INACTIVECAPTIONTEXT },
|
|
{ _t("InfoBackground"), COLOR_INFOBK },
|
|
{ _t("InfoText"), COLOR_INFOTEXT },
|
|
{ _t("Menu"), COLOR_MENU },
|
|
{ _t("MenuText"), COLOR_MENUTEXT },
|
|
{ _t("Scrollbar"), COLOR_SCROLLBAR },
|
|
{ _t("ThreeDDarkShadow"), COLOR_3DDKSHADOW },
|
|
{ _t("ThreeDFace"), COLOR_3DFACE },
|
|
{ _t("ThreeDHighlight"), COLOR_3DHILIGHT },
|
|
{ _t("ThreeDLightShadow"), COLOR_3DLIGHT },
|
|
{ _t("ThreeDShadow"), COLOR_3DSHADOW },
|
|
{ _t("Window"), COLOR_WINDOW },
|
|
{ _t("WindowFrame"), COLOR_WINDOWFRAME },
|
|
{ _t("WindowText"), COLOR_WINDOWTEXT }
|
|
};
|
|
|
|
if (color == _t("Highlight"))
|
|
{
|
|
int iii = 0;
|
|
iii++;
|
|
}
|
|
|
|
for (auto& clr : colors)
|
|
{
|
|
if (!litehtml::t_strcasecmp(clr.name, color.c_str()))
|
|
{
|
|
litehtml::tchar_t str_clr[20];
|
|
DWORD rgb_color = GetSysColor(clr.color_index);
|
|
#ifdef LITEHTML_UTF8
|
|
StringCchPrintfA(str_clr, 20, "#%02X%02X%02X", GetRValue(rgb_color), GetGValue(rgb_color), GetBValue(rgb_color));
|
|
#else
|
|
StringCchPrintf(str_clr, 20, L"#%02X%02X%02X", GetRValue(rgb_color), GetGValue(rgb_color), GetBValue(rgb_color));
|
|
#endif // LITEHTML_UTF8
|
|
return std::move(litehtml::tstring(str_clr));
|
|
}
|
|
}
|
|
return std::move(litehtml::tstring());
|
|
}
|