summaryrefslogtreecommitdiff
path: root/libs/litehtml/containers/windows
diff options
context:
space:
mode:
authorGeorge Hazan <george.hazan@gmail.com>2024-03-18 12:13:54 +0300
committerGeorge Hazan <george.hazan@gmail.com>2024-03-18 12:13:54 +0300
commit705c4d24c9c61edffc82864bf9c24384dc29a8d7 (patch)
tree4d21f87671db36b99402da3221d45b64c257c1fe /libs/litehtml/containers/windows
parent5784fc3a62b9136c6690ed45ec7b505f35512e08 (diff)
litehtml - lightweight html renderer
Diffstat (limited to 'libs/litehtml/containers/windows')
-rw-r--r--libs/litehtml/containers/windows/cairo/cairo_font.cpp374
-rw-r--r--libs/litehtml/containers/windows/cairo/cairo_font.h120
-rw-r--r--libs/litehtml/containers/windows/cairo/windows_container.cpp194
-rw-r--r--libs/litehtml/containers/windows/cairo/windows_container.h39
-rw-r--r--libs/litehtml/containers/windows/gdiplus/gdiplus_container.cpp241
-rw-r--r--libs/litehtml/containers/windows/gdiplus/gdiplus_container.h23
-rw-r--r--libs/litehtml/containers/windows/win32/win32_container.cpp426
-rw-r--r--libs/litehtml/containers/windows/win32/win32_container.h75
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(&reg);
+
+ 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();
+};