diff options
| author | George Hazan <george.hazan@gmail.com> | 2024-03-18 12:13:54 +0300 |
|---|---|---|
| committer | George Hazan <george.hazan@gmail.com> | 2024-03-18 12:13:54 +0300 |
| commit | 705c4d24c9c61edffc82864bf9c24384dc29a8d7 (patch) | |
| tree | 4d21f87671db36b99402da3221d45b64c257c1fe /libs/litehtml/containers/windows | |
| parent | 5784fc3a62b9136c6690ed45ec7b505f35512e08 (diff) | |
litehtml - lightweight html renderer
Diffstat (limited to 'libs/litehtml/containers/windows')
8 files changed, 1492 insertions, 0 deletions
diff --git a/libs/litehtml/containers/windows/cairo/cairo_font.cpp b/libs/litehtml/containers/windows/cairo/cairo_font.cpp new file mode 100644 index 0000000000..76dcaa5ee8 --- /dev/null +++ b/libs/litehtml/containers/windows/cairo/cairo_font.cpp @@ -0,0 +1,374 @@ +#include "cairo_font.h" + +cairo_font::cairo_font(IMLangFontLink2* fl, HFONT hFont, int size ) +{ + init(); + m_font_link = fl; + if(m_font_link) + { + m_font_link->AddRef(); + } + m_size = size; + set_font(hFont); +} + +cairo_font::cairo_font(IMLangFontLink2* fl, LPCWSTR facename, int size, int weight, BOOL italic, BOOL strikeout, BOOL underline ) +{ + init(); + m_size = size; + m_font_link = fl; + if(m_font_link) + { + m_font_link->AddRef(); + } + + LOGFONT lf; + ZeroMemory(&lf, sizeof(lf)); + if(!lstrcmpi(facename, L"monospace")) + { + wcscpy_s(lf.lfFaceName, LF_FACESIZE, L"Courier New"); + } else if(!lstrcmpi(facename, L"serif")) + { + wcscpy_s(lf.lfFaceName, LF_FACESIZE, L"Times New Roman"); + } else if(!lstrcmpi(facename, L"sans-serif")) + { + wcscpy_s(lf.lfFaceName, LF_FACESIZE, L"Arial"); + } else if(!lstrcmpi(facename, L"fantasy")) + { + wcscpy_s(lf.lfFaceName, LF_FACESIZE, L"Impact"); + } else if(!lstrcmpi(facename, L"cursive")) + { + wcscpy_s(lf.lfFaceName, LF_FACESIZE, L"Comic Sans MS"); + } else + { + wcscpy_s(lf.lfFaceName, LF_FACESIZE, facename); + } + + lf.lfHeight = -size; + lf.lfWeight = weight; + lf.lfItalic = italic; + lf.lfCharSet = DEFAULT_CHARSET; + lf.lfOutPrecision = OUT_DEFAULT_PRECIS; + lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; + lf.lfQuality = DEFAULT_QUALITY; + lf.lfStrikeOut = strikeout; + lf.lfUnderline = underline; + + HFONT fnt = CreateFontIndirect(&lf); + set_font(fnt); +} + +cairo_font::~cairo_font() +{ + if(m_font_face) + { + cairo_font_face_destroy(m_font_face); + } + for(size_t i = 0; i < m_linked_fonts.size(); i++) + { + if(m_linked_fonts[i]->hFont) + { + m_font_link->ReleaseFont(m_linked_fonts[i]->hFont); + } + if(m_linked_fonts[i]->font_face) + { + cairo_font_face_destroy(m_linked_fonts[i]->font_face); + } + } + m_linked_fonts.clear(); + if(m_font_link) + { + m_font_link->AddRef(); + } + if(m_hFont) + { + DeleteObject(m_hFont); + } +} + +void cairo_font::show_text( cairo_t* cr, int x, int y, const char* str ) +{ + lock(); + text_chunk::vector chunks; + split_text(str, chunks); + cairo_set_font_size(cr, m_size); + cairo_move_to(cr, x, y); + for(size_t i = 0; i < chunks.size(); i++) + { + if(chunks[i]->font) + { + cairo_set_font_face(cr, chunks[i]->font->font_face); + } else + { + cairo_set_font_face(cr, m_font_face); + } + cairo_show_text(cr, chunks[i]->text); + } + unlock(); + + if(m_bUnderline) + { + int tw = text_width(cr, chunks); + + lock(); + cairo_set_line_width(cr, 1); + cairo_move_to(cr, x, y + 1.5); + cairo_line_to(cr, x + tw, y + 1.5); + cairo_stroke(cr); + unlock(); + } + if(m_bStrikeOut) + { + int tw = text_width(cr, chunks); + + cairo_font_metrics fm; + get_metrics(cr, &fm); + + int ln_y = y - fm.x_height / 2; + + lock(); + cairo_set_line_width(cr, 1); + cairo_move_to(cr, x, (double) ln_y - 0.5); + cairo_line_to(cr, x + tw, (double) ln_y - 0.5); + cairo_stroke(cr); + unlock(); + } + + free_text_chunks(chunks); +} + +void cairo_font::split_text( const char* src, text_chunk::vector& chunks ) +{ + auto str = cairo_font::utf8_to_wchar(src); + const wchar_t* str_start = str.c_str(); + + int cch = str.length(); + + HDC hdc = GetDC(NULL); + SelectObject(hdc, m_hFont); + HRESULT hr = S_OK; + while(cch > 0) + { + DWORD dwActualCodePages; + long cchActual; + if(m_font_link) + { + hr = m_font_link->GetStrCodePages(str.c_str(), cch, m_font_code_pages, &dwActualCodePages, &cchActual); + } else + { + hr = S_FALSE; + } + + if(hr != S_OK) + { + break; + } + + text_chunk* chk = new text_chunk; + + int sz = WideCharToMultiByte(CP_UTF8, 0, str.c_str(), cchActual, chk->text, 0, NULL, NULL) + 1; + chk->text = new CHAR[sz]; + sz = WideCharToMultiByte(CP_UTF8, 0, str.c_str(), cchActual, chk->text, sz, NULL, NULL); + chk->text[sz] = 0; + chk->font = NULL; + + if(!(dwActualCodePages & m_font_code_pages)) + { + for(linked_font::vector::iterator i = m_linked_fonts.begin(); i != m_linked_fonts.end(); i++) + { + if((*i)->code_pages == dwActualCodePages) + { + chk->font = (*i); + break; + } + } + if(!chk->font) + { + linked_font* lkf = new linked_font; + lkf->code_pages = dwActualCodePages; + lkf->hFont = NULL; + m_font_link->MapFont(hdc, dwActualCodePages, 0, &lkf->hFont); + if (lkf->hFont) + { + lkf->font_face = create_font_face(lkf->hFont); + m_linked_fonts.push_back(lkf); + } + else + { + delete lkf; + lkf = NULL; + } + chk->font = lkf; + } + } + + chunks.push_back(chk); + + cch -= cchActual; + str += cchActual; + } + + if(hr != S_OK) + { + text_chunk* chk = new text_chunk; + + int sz = WideCharToMultiByte(CP_UTF8, 0, str.c_str(), -1, chk->text, 0, NULL, NULL) + 1; + chk->text = new CHAR[sz]; + sz = WideCharToMultiByte(CP_UTF8, 0, str.c_str(), -1, chk->text, sz, NULL, NULL); + chk->text[sz] = 0; + chk->font = NULL; + chunks.push_back(chk); + } + + ReleaseDC(NULL, hdc); +} + +void cairo_font::free_text_chunks( text_chunk::vector& chunks ) +{ + for(size_t i = 0; i < chunks.size(); i++) + { + delete chunks[i]; + } + chunks.clear(); +} + +cairo_font_face_t* cairo_font::create_font_face( HFONT fnt ) +{ + LOGFONT lf; + GetObject(fnt, sizeof(LOGFONT), &lf); + return cairo_win32_font_face_create_for_logfontw(&lf); +} + +int cairo_font::text_width( cairo_t* cr, const char* str ) +{ + text_chunk::vector chunks; + split_text(str, chunks); + + int ret = text_width(cr, chunks); + + free_text_chunks(chunks); + + return (int) ret; +} + +int cairo_font::text_width( cairo_t* cr, text_chunk::vector& chunks ) +{ + lock(); + cairo_set_font_size(cr, m_size); + double ret = 0; + for(size_t i = 0; i < chunks.size(); i++) + { + if(chunks[i]->font) + { + cairo_set_font_face(cr, chunks[i]->font->font_face); + } else + { + cairo_set_font_face(cr, m_font_face); + } + cairo_text_extents_t ext; + cairo_text_extents(cr, chunks[i]->text, &ext); + ret += ext.x_advance; + } + unlock(); + + return (int) ret; +} + +void cairo_font::get_metrics(cairo_t* cr, cairo_font_metrics* fm ) +{ + lock(); + cairo_set_font_face(cr, m_font_face); + cairo_set_font_size(cr, m_size); + cairo_font_extents_t ext; + cairo_font_extents(cr, &ext); + + cairo_text_extents_t tex; + cairo_text_extents(cr, "x", &tex); + + fm->ascent = (int) ext.ascent; + fm->descent = (int) ext.descent; + fm->height = (int) (ext.ascent + ext.descent); + fm->x_height = (int) tex.height; + unlock(); +} + +void cairo_font::set_font( HFONT hFont ) +{ + clear(); + + m_hFont = hFont; + m_font_face = create_font_face(m_hFont); + m_font_code_pages = 0; + if(m_font_link) + { + HDC hdc = GetDC(NULL); + SelectObject(hdc, m_hFont); + m_font_link->GetFontCodePages(hdc, m_hFont, &m_font_code_pages); + ReleaseDC(NULL, hdc); + } + LOGFONT lf; + GetObject(m_hFont, sizeof(LOGFONT), &lf); + m_bUnderline = lf.lfUnderline; + m_bStrikeOut = lf.lfStrikeOut; +} + +void cairo_font::clear() +{ + if(m_font_face) + { + cairo_font_face_destroy(m_font_face); + m_font_face = NULL; + } + for(size_t i = 0; i < m_linked_fonts.size(); i++) + { + if(m_linked_fonts[i]->hFont && m_font_link) + { + m_font_link->ReleaseFont(m_linked_fonts[i]->hFont); + } + if(m_linked_fonts[i]->font_face) + { + cairo_font_face_destroy(m_linked_fonts[i]->font_face); + } + } + m_linked_fonts.clear(); + if(m_hFont) + { + DeleteObject(m_hFont); + m_hFont = NULL; + } +} + +void cairo_font::init() +{ + m_hFont = NULL; + m_font_face = NULL; + m_font_link = NULL; + m_font_code_pages = 0; + m_size = 0; + m_bUnderline = FALSE; + m_bStrikeOut = FALSE; +} + +std::wstring cairo_font::utf8_to_wchar(const std::string& src ) +{ + if (src.empty()) return std::wstring(); + + int len = (int) src.size(); + wchar_t* str = new wchar_t[len + 1]; + MultiByteToWideChar(CP_UTF8, 0, src.c_str(), -1, str, len + 1); + std::wstring ret(str); + delete str; + return ret; +} + +std::string cairo_font::wchar_to_utf8(const std::wstring& src) +{ + if(src.empty()) return std::string(); + + int len = WideCharToMultiByte(CP_UTF8, 0, src.c_str(), -1, NULL, 0, NULL, NULL); + char* str = new char[len]; + WideCharToMultiByte(CP_UTF8, 0, src.c_str(), -1, str, len, NULL, NULL); + std::string ret(str); + delete str; + return ret; +} diff --git a/libs/litehtml/containers/windows/cairo/cairo_font.h b/libs/litehtml/containers/windows/cairo/cairo_font.h new file mode 100644 index 0000000000..fc9dd84edf --- /dev/null +++ b/libs/litehtml/containers/windows/cairo/cairo_font.h @@ -0,0 +1,120 @@ +#pragma once + +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include <windows.h> +#include <stdlib.h> +#include <malloc.h> +#include <memory.h> +#include <tchar.h> +#include <mlang.h> +#include <vector> +#include <cairo.h> +#include <cairo-win32.h> +#include <litehtml.h> + +struct linked_font +{ + typedef std::vector<linked_font*> vector; + + DWORD code_pages; + HFONT hFont; + cairo_font_face_t* font_face; +}; + +struct text_chunk +{ + typedef std::vector<text_chunk*> vector; + + char* text; + linked_font* font; + + ~text_chunk() + { + if(text) + { + delete text; + } + } +}; + +struct cairo_font_metrics +{ + int height; + int ascent; + int descent; + int x_height; +}; + + +class cairo_font +{ + HFONT m_hFont; + cairo_font_face_t* m_font_face; + IMLangFontLink2* m_font_link; + DWORD m_font_code_pages; + linked_font::vector m_linked_fonts; + int m_size; + BOOL m_bUnderline; + BOOL m_bStrikeOut; + cairo_font_metrics m_metrics; +public: + // fonts are not thread safe :( + // you have to declare and initialize cairo_font::m_sync before the first using. + static CRITICAL_SECTION m_sync; + + cairo_font(IMLangFontLink2* fl, HFONT hFont, int size); + cairo_font(IMLangFontLink2* fl, LPCWSTR facename, int size, int weight, BOOL italic, BOOL strikeout, BOOL underline); + + void init(); + ~cairo_font(); + + void show_text(cairo_t* cr, int x, int y, const char*); + int text_width(cairo_t* cr, const char* str); + void load_metrics(cairo_t* cr); + cairo_font_metrics& metrics(); + static std::wstring utf8_to_wchar(const std::string& src); + static std::string wchar_to_utf8(const std::wstring& src); +private: + void split_text(const char* str, text_chunk::vector& chunks); + void free_text_chunks(text_chunk::vector& chunks); + cairo_font_face_t* create_font_face(HFONT fnt); + void set_font(HFONT hFont); + void clear(); + int text_width(cairo_t* cr, text_chunk::vector& chunks); + void lock(); + void unlock(); + int round_d(double val); + void get_metrics(cairo_t* cr, cairo_font_metrics* fm); +}; + +inline void cairo_font::lock() +{ + EnterCriticalSection(&m_sync); +} + +inline void cairo_font::unlock() +{ + LeaveCriticalSection(&m_sync); +} + +inline int cairo_font::round_d(double val) +{ + int int_val = (int) val; + if(val - int_val >= 0.5) + { + int_val++; + } + return int_val; +} + +inline cairo_font_metrics& cairo_font::metrics() +{ + return m_metrics; +} + +inline void cairo_font::load_metrics(cairo_t* cr) +{ + get_metrics(cr, &m_metrics); +} diff --git a/libs/litehtml/containers/windows/cairo/windows_container.cpp b/libs/litehtml/containers/windows/cairo/windows_container.cpp new file mode 100644 index 0000000000..e19ad337e7 --- /dev/null +++ b/libs/litehtml/containers/windows/cairo/windows_container.cpp @@ -0,0 +1,194 @@ +#include "windows_container.h" +#define _USE_MATH_DEFINES +#include <math.h> +#include "cairo_font.h" +#include <strsafe.h> + +windows_container::windows_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); +} + +windows_container::~windows_container(void) +{ + clear_images(); + if(m_font_link) + { + m_font_link->Release(); + } + cairo_surface_destroy(m_temp_surface); + cairo_destroy(m_temp_cr); +} + +litehtml::uint_ptr windows_container::create_font( const char* 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, ","); + if(!fonts.empty()) + { + litehtml::trim(fonts[0]); + fnt_name = cairo_font::utf8_to_wchar(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); + } + } + + cairo_font* fnt = new cairo_font( m_font_link, + fnt_name.c_str(), + size, + weight, + (italic == litehtml::font_style_italic) ? 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::font_style_italic || decoration) + { + fm->draw_spaces = true; + } else + { + fm->draw_spaces = false; + } + } + + cairo_restore(m_temp_cr); + + return (litehtml::uint_ptr) fnt; +} + +void windows_container::delete_font( litehtml::uint_ptr hFont ) +{ + cairo_font* fnt = (cairo_font*) hFont; + if(fnt) + { + delete fnt; + } +} + +int windows_container::text_width( const char* 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 windows_container::draw_text( litehtml::uint_ptr hdc, const char* 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); + } +} + +litehtml::string windows_container::resolve_color(const litehtml::string& color) const +{ + struct custom_color + { + const char* name; + int color_index; + }; + + static custom_color colors[] = { + { "ActiveBorder", COLOR_ACTIVEBORDER}, + { "ActiveCaption", COLOR_ACTIVECAPTION}, + { "AppWorkspace", COLOR_APPWORKSPACE }, + { "Background", COLOR_BACKGROUND }, + { "ButtonFace", COLOR_BTNFACE }, + { "ButtonHighlight", COLOR_BTNHIGHLIGHT }, + { "ButtonShadow", COLOR_BTNSHADOW }, + { "ButtonText", COLOR_BTNTEXT }, + { "CaptionText", COLOR_CAPTIONTEXT }, + { "GrayText", COLOR_GRAYTEXT }, + { "Highlight", COLOR_HIGHLIGHT }, + { "HighlightText", COLOR_HIGHLIGHTTEXT }, + { "InactiveBorder", COLOR_INACTIVEBORDER }, + { "InactiveCaption", COLOR_INACTIVECAPTION }, + { "InactiveCaptionText", COLOR_INACTIVECAPTIONTEXT }, + { "InfoBackground", COLOR_INFOBK }, + { "InfoText", COLOR_INFOTEXT }, + { "Menu", COLOR_MENU }, + { "MenuText", COLOR_MENUTEXT }, + { "Scrollbar", COLOR_SCROLLBAR }, + { "ThreeDDarkShadow", COLOR_3DDKSHADOW }, + { "ThreeDFace", COLOR_3DFACE }, + { "ThreeDHighlight", COLOR_3DHILIGHT }, + { "ThreeDLightShadow", COLOR_3DLIGHT }, + { "ThreeDShadow", COLOR_3DSHADOW }, + { "Window", COLOR_WINDOW }, + { "WindowFrame", COLOR_WINDOWFRAME }, + { "WindowText", COLOR_WINDOWTEXT } + }; + + for (auto& clr : colors) + { + if (!litehtml::t_strcasecmp(clr.name, color.c_str())) + { + char str_clr[20]; + DWORD rgb_color = GetSysColor(clr.color_index); + StringCchPrintfA(str_clr, 20, "#%02X%02X%02X", GetRValue(rgb_color), GetGValue(rgb_color), GetBValue(rgb_color)); + return std::move(litehtml::string(str_clr)); + } + } + return std::move(litehtml::string()); +} + +cairo_surface_t* windows_container::get_image(const std::string& url) +{ + return nullptr; +} + +double windows_container::get_screen_dpi() const +{ + HDC hdc = GetDC(NULL); + int ret = GetDeviceCaps(hdc, LOGPIXELSX); + ReleaseDC(NULL, hdc); + return ret; +} + +int windows_container::get_screen_width() const +{ + HDC hdc = GetDC(NULL); + int ret = GetDeviceCaps(hdc, HORZRES); + ReleaseDC(NULL, hdc); + return ret; +} +int windows_container::get_screen_height() const +{ + HDC hdc = GetDC(NULL); + int ret = GetDeviceCaps(hdc, VERTRES); + ReleaseDC(NULL, hdc); + return ret; +} diff --git a/libs/litehtml/containers/windows/cairo/windows_container.h b/libs/litehtml/containers/windows/cairo/windows_container.h new file mode 100644 index 0000000000..daae519cab --- /dev/null +++ b/libs/litehtml/containers/windows/cairo/windows_container.h @@ -0,0 +1,39 @@ +#pragma once +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include <windows.h> +#include <mlang.h> +#include <stdlib.h> +#include <malloc.h> +#include <memory.h> +#include <tchar.h> +#include <vector> +#include "cairo.h" +#include "cairo-win32.h" +#include <litehtml.h> +#include <dib.h> +#include <txdib.h> +#include "../../libs/litehtml/containers/cairo/container_cairo.h" + +class windows_container : public container_cairo +{ +protected: + cairo_surface_t* m_temp_surface; + cairo_t* m_temp_cr; + IMLangFontLink2* m_font_link; +public: + windows_container(void); + virtual ~windows_container(void); + + litehtml::uint_ptr create_font(const char* faceName, int size, int weight, litehtml::font_style italic, unsigned int decoration, litehtml::font_metrics* fm) override; + void delete_font(litehtml::uint_ptr hFont) override; + int text_width(const char* text, litehtml::uint_ptr hFont) override; + void draw_text(litehtml::uint_ptr hdc, const char* text, litehtml::uint_ptr hFont, litehtml::web_color color, const litehtml::position& pos) override; + litehtml::string resolve_color(const litehtml::string& color) const override; + + cairo_surface_t* get_image(const std::string& url) override; + double get_screen_dpi() const override; + int get_screen_width() const override; + int get_screen_height() const override; +}; diff --git a/libs/litehtml/containers/windows/gdiplus/gdiplus_container.cpp b/libs/litehtml/containers/windows/gdiplus/gdiplus_container.cpp new file mode 100644 index 0000000000..bebd816037 --- /dev/null +++ b/libs/litehtml/containers/windows/gdiplus/gdiplus_container.cpp @@ -0,0 +1,241 @@ +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include <windows.h> +#include <gdiplus.h> +#include "gdiplus_container.h" +#pragma comment(lib, "gdiplus.lib") +using namespace Gdiplus; +using namespace litehtml; + +gdiplus_container::gdiplus_container() +{ + GdiplusStartupInput gdiplusStartupInput; + GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL); +} + +gdiplus_container::~gdiplus_container() +{ + clear_images(); + GdiplusShutdown(m_gdiplusToken); +} + +static Color gdiplus_color(web_color color) +{ + return Color(color.alpha, color.red, color.green, color.blue); +} + +void gdiplus_container::draw_ellipse(HDC hdc, int x, int y, int width, int height, web_color color, int line_width) +{ + Graphics graphics(hdc); + + graphics.SetCompositingQuality(CompositingQualityHighQuality); + graphics.SetSmoothingMode(SmoothingModeAntiAlias); + + Pen pen(gdiplus_color(color)); + graphics.DrawEllipse(&pen, x, y, width, height); +} + +void gdiplus_container::fill_ellipse(HDC hdc, int x, int y, int width, int height, web_color color) +{ + Graphics graphics(hdc); + + graphics.SetCompositingQuality(CompositingQualityHighQuality); + graphics.SetSmoothingMode(SmoothingModeAntiAlias); + + SolidBrush brush(gdiplus_color(color)); + graphics.FillEllipse(&brush, x, y, width, height); +} + +void gdiplus_container::fill_rect(HDC hdc, int x, int y, int width, int height, web_color color) +{ + Graphics graphics(hdc); + + SolidBrush brush(gdiplus_color(color)); + graphics.FillRectangle(&brush, x, y, width, height); +} + +void gdiplus_container::get_img_size(uint_ptr img, size& sz) +{ + Bitmap* bmp = (Bitmap*)img; + if (bmp) + { + sz.width = bmp->GetWidth(); + sz.height = bmp->GetHeight(); + } +} + +void gdiplus_container::free_image(uint_ptr img) +{ + Bitmap* bmp = (Bitmap*)img; + delete bmp; +} + +void gdiplus_container::draw_img_bg(HDC hdc, uint_ptr img, const background_paint& bg) +{ + Bitmap* bgbmp = (Bitmap*)img; + + Graphics graphics(hdc); + graphics.SetInterpolationMode(InterpolationModeNearestNeighbor); + graphics.SetPixelOffsetMode(PixelOffsetModeHalf); + + Region reg(Rect(bg.border_box.left(), bg.border_box.top(), bg.border_box.width, bg.border_box.height)); + graphics.SetClip(®); + + Bitmap* scaled_img = nullptr; + if (bg.image_size.width != bgbmp->GetWidth() || bg.image_size.height != bgbmp->GetHeight()) + { + scaled_img = new Bitmap(bg.image_size.width, bg.image_size.height); + Graphics gr(scaled_img); + gr.SetPixelOffsetMode(PixelOffsetModeHighQuality); + gr.DrawImage(bgbmp, 0, 0, bg.image_size.width, bg.image_size.height); + bgbmp = scaled_img; + } + + switch (bg.repeat) + { + case background_repeat_no_repeat: + { + graphics.DrawImage(bgbmp, bg.position_x, bg.position_y, bgbmp->GetWidth(), bgbmp->GetHeight()); + } + break; + case background_repeat_repeat_x: + { + CachedBitmap bmp(bgbmp, &graphics); + int x = bg.position_x; + while(x > bg.clip_box.left()) x -= bgbmp->GetWidth(); + for(; x < bg.clip_box.right(); x += bgbmp->GetWidth()) + { + graphics.DrawCachedBitmap(&bmp, x, bg.position_y); + } + } + break; + case background_repeat_repeat_y: + { + CachedBitmap bmp(bgbmp, &graphics); + int y = bg.position_y; + while(y > bg.clip_box.top()) y -= bgbmp->GetHeight(); + for(; y < bg.clip_box.bottom(); y += bgbmp->GetHeight()) + { + graphics.DrawCachedBitmap(&bmp, bg.position_x, y); + } + } + break; + case background_repeat_repeat: + { + CachedBitmap bmp(bgbmp, &graphics); + int x = bg.position_x; + while(x > bg.clip_box.left()) x -= bgbmp->GetWidth(); + int y0 = bg.position_y; + while(y0 > bg.clip_box.top()) y0 -= bgbmp->GetHeight(); + + for(; x < bg.clip_box.right(); x += bgbmp->GetWidth()) + { + for(int y = y0; y < bg.clip_box.bottom(); y += bgbmp->GetHeight()) + { + graphics.DrawCachedBitmap(&bmp, x, y); + } + } + } + break; + } + + delete scaled_img; +} + +// length of dash and space for "dashed" style, in multiples of pen width +const float dash = 3; +const float space = 2; + +static void draw_horz_border(Graphics& graphics, const border& border, int y, int left, int right) +{ + if (border.style != border_style_double || border.width < 3) + { + if (border.width == 1) right--; // 1px-wide lines are longer by one pixel in GDI+ (the endpoint is also drawn) + Pen pen(gdiplus_color(border.color), (float)border.width); + if (border.style == border_style_dotted) + { + float dashValues[2] = { 1, 1 }; + pen.SetDashPattern(dashValues, 2); + } + else if (border.style == border_style_dashed) + { + float dashValues[2] = { dash, space }; + pen.SetDashPattern(dashValues, 2); + } + graphics.DrawLine(&pen, + Point(left, y + border.width / 2), + Point(right, y + border.width / 2)); + } + else + { + int single_line_width = (int)round(border.width / 3.); + if (single_line_width == 1) right--; + Pen pen(gdiplus_color(border.color), (float)single_line_width); + graphics.DrawLine(&pen, + Point(left, y + single_line_width / 2), + Point(right, y + single_line_width / 2)); + graphics.DrawLine(&pen, + Point(left, y + border.width - 1 - single_line_width / 2), + Point(right, y + border.width - 1 - single_line_width / 2)); + } +} + +static void draw_vert_border(Graphics& graphics, const border& border, int x, int top, int bottom) +{ + if (border.style != border_style_double || border.width < 3) + { + if (border.width == 1) bottom--; + Pen pen(gdiplus_color(border.color), (float)border.width); + if (border.style == border_style_dotted) + { + float dashValues[2] = { 1, 1 }; + pen.SetDashPattern(dashValues, 2); + } + else if (border.style == border_style_dashed) + { + float dashValues[2] = { dash, space }; + pen.SetDashPattern(dashValues, 2); + } + graphics.DrawLine(&pen, + Point(x + border.width / 2, top), + Point(x + border.width / 2, bottom)); + } + else + { + int single_line_width = (int)round(border.width / 3.); + if (single_line_width == 1) bottom--; + Pen pen(gdiplus_color(border.color), (float)single_line_width); + graphics.DrawLine(&pen, + Point(x + single_line_width / 2, top), + Point(x + single_line_width / 2, bottom)); + graphics.DrawLine(&pen, + Point(x + border.width - 1 - single_line_width / 2, top), + Point(x + border.width - 1 - single_line_width / 2, bottom)); + } +} + +void gdiplus_container::draw_borders(uint_ptr hdc, const borders& borders, const position& draw_pos, bool root) +{ + apply_clip((HDC) hdc); + Graphics graphics((HDC)hdc); + + if (borders.left.width != 0) + { + draw_vert_border(graphics, borders.left, draw_pos.left(), draw_pos.top(), draw_pos.bottom()); + } + if (borders.right.width != 0) + { + draw_vert_border(graphics, borders.right, draw_pos.right() - borders.right.width, draw_pos.top(), draw_pos.bottom()); + } + if (borders.top.width != 0) + { + draw_horz_border(graphics, borders.top, draw_pos.top(), draw_pos.left(), draw_pos.right()); + } + if (borders.bottom.width != 0) + { + draw_horz_border(graphics, borders.bottom, draw_pos.bottom() - borders.bottom.width, draw_pos.left(), draw_pos.right()); + } + + release_clip((HDC) hdc); +} diff --git a/libs/litehtml/containers/windows/gdiplus/gdiplus_container.h b/libs/litehtml/containers/windows/gdiplus/gdiplus_container.h new file mode 100644 index 0000000000..a5a61382c3 --- /dev/null +++ b/libs/litehtml/containers/windows/gdiplus/gdiplus_container.h @@ -0,0 +1,23 @@ +#pragma once +#include "..\win32\win32_container.h" + +class gdiplus_container : public win32_container +{ +public: + gdiplus_container(); + virtual ~gdiplus_container(); + +private: + ULONG_PTR m_gdiplusToken; + +protected: + // win32_container members + void draw_ellipse(HDC hdc, int x, int y, int width, int height, litehtml::web_color color, int line_width) override; + void fill_ellipse(HDC hdc, int x, int y, int width, int height, litehtml::web_color color) override; + void fill_rect(HDC hdc, int x, int y, int width, int height, litehtml::web_color color) override; + void get_img_size(uint_ptr img, litehtml::size& sz) override; + void free_image(uint_ptr img) override; + void draw_img_bg(HDC hdc, uint_ptr img, const litehtml::background_paint& bg) override; + // litehtml::document_container members + void draw_borders(uint_ptr hdc, const litehtml::borders& borders, const litehtml::position& draw_pos, bool root) override; +}; diff --git a/libs/litehtml/containers/windows/win32/win32_container.cpp b/libs/litehtml/containers/windows/win32/win32_container.cpp new file mode 100644 index 0000000000..520b1ed234 --- /dev/null +++ b/libs/litehtml/containers/windows/win32/win32_container.cpp @@ -0,0 +1,426 @@ +#include "win32_container.h" + +win32_container::win32_container() +{ + m_hClipRgn = NULL; + m_tmp_hdc = GetDC(NULL); + InitializeCriticalSection(&m_img_sync); + + EnumFonts(m_tmp_hdc, NULL, EnumFontsProc, (LPARAM)this); + m_installed_fonts.insert(L"monospace"); + m_installed_fonts.insert(L"serif"); + m_installed_fonts.insert(L"sans-serif"); + m_installed_fonts.insert(L"fantasy"); + m_installed_fonts.insert(L"cursive"); +} + +win32_container::~win32_container() +{ + DeleteCriticalSection(&m_img_sync); + if(m_hClipRgn) + { + DeleteObject(m_hClipRgn); + } + ReleaseDC(NULL, m_tmp_hdc); +} + +int CALLBACK win32_container::EnumFontsProc(const LOGFONT* lplf, const TEXTMETRIC* lptm, DWORD dwType, LPARAM lpData) +{ + win32_container* container = (win32_container*)lpData; + container->m_installed_fonts.insert(lplf->lfFaceName); + return 1; +} + +static LPCWSTR get_exact_font_name(LPCWSTR facename) +{ + if (!lstrcmpi(facename, L"monospace")) return L"Courier New"; + else if (!lstrcmpi(facename, L"serif")) return L"Times New Roman"; + else if (!lstrcmpi(facename, L"sans-serif")) return L"Arial"; + else if (!lstrcmpi(facename, L"fantasy")) return L"Impact"; + else if (!lstrcmpi(facename, L"cursive")) return L"Comic Sans MS"; + else return facename; +} + +static void trim_quotes(litehtml::string& str) +{ + if (str.front() == '"' || str.front() == '\'') + str.erase(0, 1); + + if (str.back() == '"' || str.back() == '\'') + str.erase(str.length() - 1, 1); +} + +litehtml::uint_ptr win32_container::create_font( const char* font_list, int size, int weight, litehtml::font_style italic, unsigned int decoration, litehtml::font_metrics* fm ) +{ + std::wstring font_name; + litehtml::string_vector fonts; + litehtml::split_string(font_list, fonts, ","); + bool found = false; + for (auto& name : fonts) + { + litehtml::trim(name); + trim_quotes(name); + std::wstring wname = (const wchar_t*)litehtml_to_wchar(name.c_str()); + if (m_installed_fonts.count(wname)) + { + font_name = wname; + found = true; + break; + } + } + if (!found) font_name = litehtml_to_wchar(get_default_font_name()); + font_name = get_exact_font_name(font_name.c_str()); + + LOGFONT lf = {}; + wcscpy_s(lf.lfFaceName, LF_FACESIZE, font_name.c_str()); + + lf.lfHeight = -size; + lf.lfWeight = weight; + lf.lfItalic = (italic == litehtml::font_style_italic) ? TRUE : FALSE; + lf.lfCharSet = DEFAULT_CHARSET; + lf.lfOutPrecision = OUT_DEFAULT_PRECIS; + lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; + lf.lfQuality = DEFAULT_QUALITY; + lf.lfStrikeOut = (decoration & litehtml::font_decoration_linethrough) ? TRUE : FALSE; + lf.lfUnderline = (decoration & litehtml::font_decoration_underline) ? TRUE : FALSE; + HFONT hFont = CreateFontIndirect(&lf); + + if (fm) + { + SelectObject(m_tmp_hdc, hFont); + TEXTMETRIC tm = {}; + GetTextMetrics(m_tmp_hdc, &tm); + fm->ascent = tm.tmAscent; + fm->descent = tm.tmDescent; + fm->height = tm.tmHeight; + fm->x_height = tm.tmHeight / 2; // this is an estimate; call GetGlyphOutline to get the real value + fm->draw_spaces = italic || decoration; + } + + return (uint_ptr) hFont; +} + +void win32_container::delete_font( uint_ptr hFont ) +{ + DeleteObject((HFONT) hFont); +} + +const char* win32_container::get_default_font_name() const +{ + return "Times New Roman"; +} + +int win32_container::get_default_font_size() const +{ + return 16; +} + +int win32_container::text_width( const char* text, uint_ptr hFont ) +{ + SIZE size = {}; + SelectObject(m_tmp_hdc, (HFONT)hFont); + std::wstring wtext = (const wchar_t*)litehtml_to_wchar(text); + GetTextExtentPoint32(m_tmp_hdc, wtext.c_str(), (int)wtext.size(), &size); + return size.cx; +} + +void win32_container::draw_text( uint_ptr hdc, const char* text, uint_ptr hFont, litehtml::web_color color, const litehtml::position& pos ) +{ + apply_clip((HDC) hdc); + + HFONT oldFont = (HFONT) SelectObject((HDC) hdc, (HFONT) hFont); + + SetBkMode((HDC) hdc, TRANSPARENT); + + SetTextColor((HDC) hdc, RGB(color.red, color.green, color.blue)); + + RECT rcText = { pos.left(), pos.top(), pos.right(), pos.bottom() }; + DrawText((HDC) hdc, litehtml_to_wchar(text), -1, &rcText, DT_SINGLELINE | DT_NOPREFIX | DT_BOTTOM | DT_NOCLIP); + + SelectObject((HDC) hdc, oldFont); + + release_clip((HDC) hdc); +} + +int win32_container::pt_to_px( int pt ) const +{ + return MulDiv(pt, GetDeviceCaps(m_tmp_hdc, LOGPIXELSY), 72); +} + +void win32_container::draw_list_marker(uint_ptr hdc, const litehtml::list_marker& marker) +{ + apply_clip((HDC)hdc); + + int top_margin = marker.pos.height / 3; + if (top_margin < 4) + top_margin = 0; + + int draw_x = marker.pos.x; + int draw_y = marker.pos.y + top_margin; + int draw_width = marker.pos.height - top_margin * 2; + int draw_height = marker.pos.height - top_margin * 2; + + switch (marker.marker_type) + { + case litehtml::list_style_type_circle: + { + draw_ellipse((HDC)hdc, draw_x, draw_y, draw_width, draw_height, marker.color, 1); + } + break; + case litehtml::list_style_type_disc: + { + fill_ellipse((HDC)hdc, draw_x, draw_y, draw_width, draw_height, marker.color); + } + break; + case litehtml::list_style_type_square: + { + fill_rect((HDC)hdc, draw_x, draw_y, draw_width, draw_height, marker.color); + } + break; + } + release_clip((HDC)hdc); +} + +void win32_container::make_url_utf8(const char* url, const char* basepath, std::wstring& out) +{ + make_url(litehtml::utf8_to_wchar(url), litehtml::utf8_to_wchar(basepath), out); +} + +void win32_container::load_image( const char* src, const char* baseurl, bool redraw_on_ready ) +{ + std::wstring url; + make_url_utf8(src, baseurl, url); + + lock_images_cache(); + if (m_images.count(url) == 0) + { + unlock_images_cache(); + uint_ptr img = get_image(url.c_str(), redraw_on_ready); + add_image(url.c_str(), img); + } + else + { + unlock_images_cache(); + } +} + +void win32_container::add_image(LPCWSTR url, uint_ptr img) +{ + lock_images_cache(); + m_images[url] = img; + unlock_images_cache(); +} + +void win32_container::get_image_size( const char* src, const char* baseurl, litehtml::size& sz ) +{ + std::wstring url; + make_url_utf8(src, baseurl, url); + + sz.width = 0; + sz.height = 0; + + lock_images_cache(); + images_map::iterator img = m_images.find(url); + if(img != m_images.end() && img->second) + { + get_img_size(img->second, sz); + } + unlock_images_cache(); +} + +void win32_container::clear_images() +{ + lock_images_cache(); + for(auto& img : m_images) + { + if(img.second) + { + free_image(img.second); + } + } + m_images.clear(); + unlock_images_cache(); +} + +void win32_container::lock_images_cache() +{ + EnterCriticalSection(&m_img_sync); +} + +void win32_container::unlock_images_cache() +{ + LeaveCriticalSection(&m_img_sync); +} + +void win32_container::draw_background( uint_ptr _hdc, const std::vector<litehtml::background_paint>& bg ) +{ + HDC hdc = (HDC)_hdc; + apply_clip(hdc); + + auto border_box = bg.back().border_box; + auto color = bg.back().color; + fill_rect(hdc, border_box.x, border_box.y, border_box.width, border_box.height, color); + + for (int i = (int)bg.size() - 1; i >= 0; i--) + { + std::wstring url; + make_url_utf8(bg[i].image.c_str(), bg[i].baseurl.c_str(), url); + + lock_images_cache(); + images_map::iterator img = m_images.find(url); + if (img != m_images.end() && img->second) + { + draw_img_bg(hdc, img->second, bg[i]); + } + unlock_images_cache(); + } + + release_clip(hdc); +} + +void win32_container::set_clip( const litehtml::position& pos, const litehtml::border_radiuses& bdr_radius ) +{ + m_clips.push_back(pos); +} + +void win32_container::del_clip() +{ + if(!m_clips.empty()) + { + m_clips.pop_back(); + } +} + +void win32_container::apply_clip(HDC hdc) +{ + if(m_hClipRgn) + { + DeleteObject(m_hClipRgn); + m_hClipRgn = NULL; + } + + if(!m_clips.empty()) + { + POINT ptView = {0, 0}; + GetWindowOrgEx(hdc, &ptView); + + litehtml::position clip_pos = m_clips.back(); + m_hClipRgn = CreateRectRgn(clip_pos.left() - ptView.x, clip_pos.top() - ptView.y, clip_pos.right() - ptView.x, clip_pos.bottom() - ptView.y); + SelectClipRgn(hdc, m_hClipRgn); + } +} + +void win32_container::release_clip(HDC hdc) +{ + SelectClipRgn(hdc, NULL); + + if(m_hClipRgn) + { + DeleteObject(m_hClipRgn); + m_hClipRgn = NULL; + } +} + +litehtml::element::ptr win32_container::create_element(const char* tag_name, const litehtml::string_map& attributes, const litehtml::document::ptr& doc) +{ + return 0; +} + +void win32_container::get_media_features(litehtml::media_features& media) const +{ + litehtml::position client; + get_client_rect(client); + + 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(m_tmp_hdc, LOGPIXELSX); + media.device_width = GetDeviceCaps(m_tmp_hdc, HORZRES); + media.device_height = GetDeviceCaps(m_tmp_hdc, VERTRES); +} + +void win32_container::get_language(litehtml::string& language, litehtml::string& culture) const +{ + language = "en"; + culture = ""; +} + +void win32_container::transform_text(litehtml::string& text, litehtml::text_transform tt) +{ + if (text.empty()) return; + + LPWSTR txt = _wcsdup(litehtml_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; + } + text = litehtml_from_wchar(txt); + free(txt); +} + +void win32_container::link(const litehtml::document::ptr& doc, const litehtml::element::ptr& el) +{ +} + +litehtml::string win32_container::resolve_color(const litehtml::string& color) const +{ + struct custom_color + { + const char* name; + int color_index; + }; + + static custom_color colors[] = { + { "ActiveBorder", COLOR_ACTIVEBORDER }, + { "ActiveCaption", COLOR_ACTIVECAPTION }, + { "AppWorkspace", COLOR_APPWORKSPACE }, + { "Background", COLOR_BACKGROUND }, + { "ButtonFace", COLOR_BTNFACE }, + { "ButtonHighlight", COLOR_BTNHIGHLIGHT }, + { "ButtonShadow", COLOR_BTNSHADOW }, + { "ButtonText", COLOR_BTNTEXT }, + { "CaptionText", COLOR_CAPTIONTEXT }, + { "GrayText", COLOR_GRAYTEXT }, + { "Highlight", COLOR_HIGHLIGHT }, + { "HighlightText", COLOR_HIGHLIGHTTEXT }, + { "InactiveBorder", COLOR_INACTIVEBORDER }, + { "InactiveCaption", COLOR_INACTIVECAPTION }, + { "InactiveCaptionText", COLOR_INACTIVECAPTIONTEXT }, + { "InfoBackground", COLOR_INFOBK }, + { "InfoText", COLOR_INFOTEXT }, + { "Menu", COLOR_MENU }, + { "MenuText", COLOR_MENUTEXT }, + { "Scrollbar", COLOR_SCROLLBAR }, + { "ThreeDDarkShadow", COLOR_3DDKSHADOW }, + { "ThreeDFace", COLOR_3DFACE }, + { "ThreeDHighlight", COLOR_3DHILIGHT }, + { "ThreeDLightShadow", COLOR_3DLIGHT }, + { "ThreeDShadow", COLOR_3DSHADOW }, + { "Window", COLOR_WINDOW }, + { "WindowFrame", COLOR_WINDOWFRAME }, + { "WindowText", COLOR_WINDOWTEXT } + }; + + for (auto& clr : colors) + { + if (!litehtml::t_strcasecmp(color.c_str(), clr.name)) + { + char str_clr[20]; + DWORD rgb_color = GetSysColor(clr.color_index); + t_snprintf(str_clr, 20, "#%02X%02X%02X", GetRValue(rgb_color), GetGValue(rgb_color), GetBValue(rgb_color)); + return std::move(litehtml::string(str_clr)); + } + } + return std::move(litehtml::string()); +} diff --git a/libs/litehtml/containers/windows/win32/win32_container.h b/libs/litehtml/containers/windows/win32/win32_container.h new file mode 100644 index 0000000000..93a9d81086 --- /dev/null +++ b/libs/litehtml/containers/windows/win32/win32_container.h @@ -0,0 +1,75 @@ +#pragma once +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include <windows.h> +#include <set> +#include <litehtml.h> + +class win32_container : public litehtml::document_container +{ +public: + typedef litehtml::uint_ptr uint_ptr; + typedef std::map<std::wstring, uint_ptr> images_map; + +protected: + images_map m_images; + litehtml::position::vector m_clips; + HRGN m_hClipRgn; + std::set<std::wstring> m_installed_fonts; + HDC m_tmp_hdc; + CRITICAL_SECTION m_img_sync; + +public: + win32_container(); + virtual ~win32_container(); + + // litehtml::document_container members + uint_ptr create_font(const char* faceName, int size, int weight, litehtml::font_style italic, unsigned int decoration, litehtml::font_metrics* fm) override; + void delete_font(uint_ptr hFont) override; + const char* get_default_font_name() const override; + int get_default_font_size() const override; + int text_width(const char* text, uint_ptr hFont) override; + void draw_text(uint_ptr hdc, const char* text, uint_ptr hFont, litehtml::web_color color, const litehtml::position& pos) override; + void transform_text(litehtml::string& text, litehtml::text_transform tt) override; + + int pt_to_px(int pt) const override; + void draw_list_marker(uint_ptr hdc, const litehtml::list_marker& marker) override; + void load_image(const char* src, const char* baseurl, bool redraw_on_ready) override; + void get_image_size(const char* src, const char* baseurl, litehtml::size& sz) override; + void draw_background(uint_ptr hdc, const std::vector<litehtml::background_paint>& bg) override; + + void set_clip(const litehtml::position& pos, const litehtml::border_radiuses& bdr_radius) override; + void del_clip() override; + litehtml::element::ptr create_element(const char* tag_name, const litehtml::string_map& attributes, const litehtml::document::ptr& doc) override; + void get_media_features(litehtml::media_features& media) const override; + void get_language(litehtml::string& language, litehtml::string& culture) const override; + void link(const litehtml::document::ptr& doc, const litehtml::element::ptr& el) override; + litehtml::string resolve_color(const litehtml::string& color) const override; + +protected: + void apply_clip(HDC hdc); + void release_clip(HDC hdc); + + virtual void make_url(LPCWSTR url, LPCWSTR basepath, std::wstring& out) = 0; + void make_url_utf8(const char* url, const char* basepath, std::wstring& out); + virtual void get_client_rect(litehtml::position& client) const = 0; + + // get_image is called by load_image. + // if url_or_path is URL then get_image may return 0, the image should be added later by add_image when it becomes available + virtual uint_ptr get_image(LPCWSTR url_or_path, bool redraw_on_ready) = 0; + void add_image(LPCWSTR url, uint_ptr img); + void clear_images(); + virtual void free_image(uint_ptr img) = 0; + virtual void get_img_size(uint_ptr img, litehtml::size& sz) = 0; + virtual void draw_img_bg(HDC hdc, uint_ptr img, const litehtml::background_paint& bg) = 0; + + virtual void draw_ellipse(HDC hdc, int x, int y, int width, int height, litehtml::web_color color, int line_width) = 0; + virtual void fill_ellipse(HDC hdc, int x, int y, int width, int height, litehtml::web_color color) = 0; + virtual void fill_rect(HDC hdc, int x, int y, int width, int height, litehtml::web_color color) = 0; + +private: + static int CALLBACK EnumFontsProc(const LOGFONT* lplf, const TEXTMETRIC* lptm, DWORD dwType, LPARAM lpData); + void lock_images_cache(); + void unlock_images_cache(); +}; |
