litehtml/containers/cairo/cairo_font.cpp
2018-05-25 17:05:49 +03:00

379 lines
7.7 KiB
C++

#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 litehtml::tchar_t* 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 litehtml::tchar_t* src, text_chunk::vector& chunks )
{
wchar_t* str;
#ifdef LITEHTML_UTF8
str = cairo_font::utf8_to_wchar(src);
wchar_t* str_start = str;
#else
str = (wchar_t*) src;
#endif
int cch = lstrlen(str);
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, 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, cchActual, chk->text, 0, NULL, NULL) + 1;
chk->text = new CHAR[sz];
sz = WideCharToMultiByte(CP_UTF8, 0, 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, -1, chk->text, 0, NULL, NULL) + 1;
chk->text = new CHAR[sz];
sz = WideCharToMultiByte(CP_UTF8, 0, str, -1, chk->text, sz, NULL, NULL);
chk->text[sz] = 0;
chk->font = NULL;
chunks.push_back(chk);
}
ReleaseDC(NULL, hdc);
#ifdef LITEHTML_UTF8
delete str_start;
#endif
}
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 litehtml::tchar_t* 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;
}
wchar_t* cairo_font::utf8_to_wchar( const char* src )
{
if(!src) return NULL;
int len = (int) strlen(src);
wchar_t* ret = new wchar_t[len + 1];
MultiByteToWideChar(CP_UTF8, 0, src, -1, ret, len + 1);
return ret;
}
char* cairo_font::wchar_to_utf8( const wchar_t* src )
{
if(!src) return NULL;
int len = WideCharToMultiByte(CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL);
char* ret = new char[len];
WideCharToMultiByte(CP_UTF8, 0, src, -1, ret, len, NULL, NULL);
return ret;
}