379 lines
7.7 KiB
C++
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;
|
|
} |