mactype/fteng.cpp
2020-12-06 11:38:08 +01:00

1071 lines
29 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "override.h"
#include "ft.h"
#include <windows.h>
#include <tchar.h>
#include "fteng.h"
#ifdef _DLL
#pragma comment(linker, "/nod:msvcprt.lib /nod:msvcprtd.lib")
#endif
#if 0
#define FREETYPE_REQCOUNTMAX 10
#define GC_TRACE TRACE
#define FREETYPE_GC_COUNTER 128
#else
#define FREETYPE_REQCOUNTMAX 2048//默认4096,每缓存该数量的文字将刷新缓存降低内存占用
#define GC_TRACE NOP_FUNCTION
#define FREETYPE_GC_COUNTER 1024//刷新缓存后保留文字数量
#endif
FreeTypeFontEngine* g_pFTEngine;
FT_Library freetype_library;
FTC_Manager cache_man;
FTC_CMapCache cmap_cache;
FTC_ImageCache image_cache;
CTLSDCArray TLSDCArray;
int CALLBACK EnumFontCallBack(const LOGFONT *lplf, const TEXTMETRIC *lptm, DWORD /*FontType*/, LPARAM lParam)
{
LOGFONT * lf=(LOGFONT *)lParam;
StringCchCopy(lf->lfFaceName, LF_FACESIZE, lplf->lfFaceName);
lf->lfQuality=0x2d; //magic number
return 0;
}
bool GetFontLocalName(TCHAR* pszFontName, __out TCHAR* pszNameOut) //获得字体的本地化名称,返回值为字体是否存在
{
LOGFONT lf = {0};
TCHAR* ret;
lf.lfQuality = 0x2d;
if (!(ret = FontNameCache.Find((TCHAR*)pszFontName)))
{
StringCchCopy(lf.lfFaceName, LF_FACESIZE, pszFontName);
lf.lfCharSet=DEFAULT_CHARSET;
HDC dc=GetDC(NULL);
lf.lfQuality=0;
EnumFontFamiliesEx(dc, &lf, &EnumFontCallBack, (LPARAM)&lf, 0);
ReleaseDC(NULL, dc);
if (lf.lfQuality==0x2d)
FontNameCache.Add((TCHAR*)pszFontName, lf.lfFaceName);
ret=lf.lfFaceName;
}
StringCchCopy(pszNameOut, LF_FACESIZE, ret);
return lf.lfQuality == 0x2d;
}
LOGFONTW* GetFontNameFromFile(LPCWSTR Filename) //获得一个字体文件内包含的所有字体名称s
{
LOGFONTW* logfonts = NULL;
DWORD bufsize=0;
if (GetFontResourceInfo(Filename, &bufsize, NULL, 2))
{
logfonts = (LOGFONTW*)malloc(bufsize+1);
if (GetFontResourceInfo(Filename, &bufsize, logfonts, 2))
{
((char*)logfonts)[bufsize]=0;
return logfonts;
}
else
{
free(logfonts);
return NULL;
}
}
else
{
AddFontResourceW(Filename);
if (GetFontResourceInfo(Filename, &bufsize, NULL, 2))
{
logfonts = (LOGFONTW*)malloc(bufsize+1);
if (GetFontResourceInfo(Filename, &bufsize, logfonts, 2))
{
((char*)logfonts)[bufsize]=0;
ORIG_RemoveFontResourceExW(Filename,0,NULL);
return logfonts;
}
else
{
free(logfonts);
ORIG_RemoveFontResourceExW(Filename,0,NULL);
return NULL;
}
}
ORIG_RemoveFontResourceExW(Filename,0,NULL);
return NULL;
}
}
template <class T>
struct GCCounterSortFunc : public std::binary_function<const T*, const T*, bool>
{
bool operator()(const T* arg1, const T* arg2) const
{
const int cnt1 = arg1 ? arg1->GetMruCounter() : -1;
const int cnt2 = arg2 ? arg2->GetMruCounter() : -1;
return cnt1 > cnt2;
}
};
struct DeleteCharFunc : public std::unary_function<FreeTypeCharData*&, void>
{
void operator()(FreeTypeCharData*& arg) const
{
if (!arg)
return;
delete arg;
arg = NULL;
}
};
template <class T>
void CompactMap(T& pp, int count, int reduce)
{
CCriticalSectionLock __lock(CCriticalSectionLock::CS_FONTCACHE);
int reducecount = pp.size() - reduce;
T::iterator it= pp.begin();
for (int i=0;i<reducecount;i++) //删除超过FREETYPE_GC_COUNTER之后的缓存
{
//it->second->Erase();
delete it->second;
pp.erase(it++);
}
return;
}
template <class T>
void Compact(T** pp, int count, int reduce)
{
Assert(count >= 0);
Assert(reduce > 0);
if (!pp || !count || count < reduce) {
return;
}
CCriticalSectionLock __lock(CCriticalSectionLock::CS_FONTCACHE);
TRACE(_T("Compact(0x%p, %d, %d)\n"), pp, count, reduce);
//GCモドキ
//T::m_mrucounterの降順に並ぶので
//reduceを超える部分を削除する
T** ppTemp = (T**)malloc(sizeof(T*) * count);
if (!ppTemp) {
return;
}
memcpy(ppTemp, pp, sizeof(T*) * count);
std::sort(ppTemp, ppTemp + count, GCCounterSortFunc<T>());
int i;
for (i=0; i<reduce; i++) {
if (!ppTemp[i])
break;
ppTemp[i]->ResetMruCounter();
}
//GC_TRACE(_T("GC:"));
for (i=reduce; i<count; i++) {
if (!ppTemp[i])
break;
//GC_TRACE(_T(" %wc"), ppTemp[i]->GetChar());
ppTemp[i]->Erase();
}
//GC_TRACE(_T("\n"));
free(ppTemp);
}
//FreeTypeCharData
FreeTypeCharData::FreeTypeCharData(FreeTypeCharData** ppCh, FreeTypeCharData** ppGl, WCHAR wch, UINT glyphindex, int width, int mru, int gdiWidth, int AAMode)
: m_ppSelfGlyph(ppGl), m_glyphindex(glyphindex), m_width(width)
, m_glyph(NULL), m_glyphMono(NULL), m_bmpSize(0), m_bmpMonoSize(0)
, FreeTypeMruCounter(mru), m_gdiWidth(gdiWidth), m_AAMode(AAMode)
{
g_pFTEngine->AddMemUsedObj(this);
AddChar(ppCh);
#ifdef _DEBUG
m_wch = wch;
#endif
}
FreeTypeCharData::~FreeTypeCharData()
{
CharDataArray& arr = m_arrSelfChar;
int n = arr.GetSize();
while (n--) {
FreeTypeCharData** pp = arr[n];
Assert(*pp == this);
*pp = NULL;
}
if(m_ppSelfGlyph) {
Assert(*m_ppSelfGlyph == this);
*m_ppSelfGlyph = NULL;
}
if(m_glyph){
FT_Done_Ref_Glyph((FT_Referenced_Glyph*)&m_glyph);
}
if(m_glyphMono){
FT_Done_Ref_Glyph((FT_Referenced_Glyph*)&m_glyphMono);
}
g_pFTEngine->SubMemUsed(m_bmpSize);
g_pFTEngine->SubMemUsed(m_bmpMonoSize);
g_pFTEngine->SubMemUsedObj(this);
}
void FreeTypeCharData::SetGlyph(FT_Render_Mode render_mode, FT_Referenced_BitmapGlyph glyph)
{
const bool bMono = (render_mode == FT_RENDER_MODE_MONO);
FT_Referenced_BitmapGlyph& gl = bMono ? m_glyphMono : m_glyph;
if (gl)
FT_Done_Ref_Glyph((FT_Referenced_Glyph*)&gl);
{
FT_Glyph_Ref_Copy((FT_Referenced_Glyph)glyph, (FT_Referenced_Glyph*)&gl);
if (gl) {
int& size = bMono ? m_bmpMonoSize : m_bmpSize;
size = FT_Bitmap_CalcSize(gl->ft_glyph);
size += sizeof(FT_BitmapGlyphRec);
g_pFTEngine->AddMemUsed(size);
}
}
}
//FreeTypeFontCache
FreeTypeFontCache::FreeTypeFontCache(/*int px, int weight, bool italic, */int mru)
: /*m_px(px), m_weight(weight), m_italic(italic), */m_active(false)
, FreeTypeMruCounter(mru)
{
#ifdef _USE_ARRAY
ZeroMemory(&m_tm, sizeof(TEXTMETRIC));
ZeroMemory(m_chars, sizeof(m_chars));
ZeroMemory(m_glyphs, sizeof(m_glyphs));
#else
m_GlyphCache.clear();
#endif
g_pFTEngine->AddMemUsedObj(this);
}
FreeTypeFontCache::~FreeTypeFontCache()
{
Erase();
g_pFTEngine->SubMemUsedObj(this);
}
void FreeTypeFontCache::Compact()
{
//TRACE(_T("FreeTypeFontCache::Compact: %d > %d\n"), countof(m_chars), FREETYPE_GC_COUNTER);
ResetGCCounter();
#ifdef _USE_ARRAY
::Compact(m_glyphs, countof(m_glyphs), FREETYPE_GC_COUNTER);
#else
::CompactMap(m_GlyphCache, m_GlyphCache.size(), FREETYPE_GC_COUNTER);
#endif
//GlyphCache::const_iterator it=m_GlyphCache.begin();
}
void FreeTypeFontCache::Erase()
{
m_active = false;
#ifdef _USE_ARRAY
std::for_each(m_chars, m_chars + FT_MAX_CHARS, DeleteCharFunc());
std::for_each(m_glyphs, m_glyphs + FT_MAX_CHARS, DeleteCharFunc());
#else
GlyphCache::iterator it=m_GlyphCache.begin();
for (;it!=m_GlyphCache.end();++it)
delete it->second;
m_GlyphCache.clear();
#endif
}
void FreeTypeFontCache::AddCharData(WCHAR wch, UINT glyphindex, int width, int gdiWidth, FT_Referenced_BitmapGlyph glyph, FT_Render_Mode render_mode, int AAMode)
{
if (glyphindex & 0xffff0000 /*|| !g_ccbCache*/) {
return;
}
if (AddIncrement() >= FREETYPE_REQCOUNTMAX) { //先压缩,避免压缩后丢失的问题
Compact();
}
#ifdef _USE_ARRAY
FreeTypeCharData** ppChar = _GetChar(wch);
if (*ppChar) {
(*ppChar)->SetGlyph(render_mode, glyph);
(*ppChar)->SetMruCounter(this);
return;
}
#else
GlyphCache::iterator it=m_GlyphCache.find(wch);
if (it!=m_GlyphCache.end()) //找到了旧数据
{
FreeTypeCharData* ppChar = it->second;
if (ppChar) {
ppChar->SetGlyph(render_mode, glyph);
ppChar->SetMruCounter(this);
ppChar->SetWidth(width);
ppChar->SetGDIWidth(gdiWidth);
return;
}
}
#endif
FreeTypeCharData* p = new FreeTypeCharData(/*ppChar*/NULL, NULL, wch, glyphindex, width, MruIncrement(), gdiWidth, AAMode);
if (p == NULL) {
return;
}
p->SetGlyph(render_mode, glyph);
#ifdef _USE_ARRAY
*ppChar = p;
#else
m_GlyphCache[wch]=p;
#endif
}
void FreeTypeFontCache::AddGlyphData(UINT glyphindex, int width, int gdiWidth, FT_Referenced_BitmapGlyph glyph, FT_Render_Mode render_mode, int AAMode)
{
if (glyphindex & 0xffff0000 /*|| !g_ccbCache*/) {
return;
}
//GC
if (AddIncrement() >= FREETYPE_REQCOUNTMAX) {
//TRACE(_T("Compact(0x%p)\n"), this);
Compact();
}
#ifdef _USE_ARRAY
FreeTypeCharData** ppGlyph = _GetGlyph(glyphindex);
if (*ppGlyph) {
(*ppGlyph)->SetGlyph(render_mode, glyph);
(*ppGlyph)->SetMruCounter(this);
return;
}
#else
GlyphCache::iterator it=m_GlyphCache.find(-(int)glyphindex);
if (it!=m_GlyphCache.end()) //找到了旧数据
{
FreeTypeCharData* ppChar = it->second;
if (ppChar) {
(ppChar)->SetGlyph(render_mode, glyph);
(ppChar)->SetMruCounter(this);
ppChar->SetWidth(width);
ppChar->SetGDIWidth(gdiWidth);
return;
}
}
#endif
//追加(glyphのみ)
FreeTypeCharData* p = new FreeTypeCharData(NULL, /*ppGlyph*/NULL, 0, glyphindex, width, MruIncrement(), gdiWidth, AAMode);
if (p == NULL) {
return;
}
p->SetGlyph(render_mode, glyph);
#ifdef _USE_ARRAY
*ppGlyph = p;
#else
m_GlyphCache[-(int)glyphindex]=p;
#endif
}
//FreeTypeFontInfo
void FreeTypeFontInfo::Compact()
{
//TRACE(_T("FreeTypeFontInfo::Compact: %d > %d\n"), m_cache.GetSize(), m_nMaxSizes);
ResetGCCounter();
::CompactMap(m_cache, m_cache.size(), m_nMaxSizes);
CacheArray::const_iterator it=m_cache.begin();
for (;it!=m_cache.end();++it)
it->second->Deactive();
}
void FreeTypeFontInfo::Createlink()
{
CFontFaceNamesEnumerator fn(m_hash.c_str(), m_nFontFamily);
std::set<int> linkset; //链接字体集合,防止重复链接,降低效率
linkset.insert(m_id);
face_id_link[m_linknum] = (FTC_FaceID)m_id;
ggo_link[m_linknum++] = m_ggoFont; //第一个链接一定是自己,不需要获取
LOGFONT lf;
BOOL IsSimSun = false;
memset(&lf, 0, sizeof(LOGFONT));
lf.lfCharSet=DEFAULT_CHARSET;
const CGdippSettings* pSettings = CGdippSettings::GetInstance();
for (fn.next() ; !fn.atend(); fn.next()) { //跳过第一个链接
//FreeTypeFontInfo* pfitemp = g_pFTEngine->FindFont(fn, m_weight, m_italic);
//if (pfitemp && pfitemp->m_isSimSun)
// IsSimSun = true;
if (!m_SimSunID)
IsSimSun = (_wcsicmp(fn,L"宋体")==0 || _wcsicmp(fn,L"SimSun")==0);
StringCchCopy(lf.lfFaceName, LF_FACESIZE, fn);
if (!_wcsicmp(fn, m_familyname.c_str())) // allow font link to itself
pSettings->CopyForceFont(lf,lf);
FreeTypeFontInfo* pfitemp = g_pFTEngine->FindFont(lf.lfFaceName, /*m_weight*/0, /*m_italic*/false);
if (pfitemp && linkset.find(pfitemp->GetId())==linkset.end()) {
linkset.insert(pfitemp->GetId());
face_id_link[m_linknum] = (FTC_FaceID)pfitemp->GetId();
ggo_link[m_linknum++] = pfitemp->GetGGOFont();
if (!m_SimSunID && IsSimSun)
m_SimSunID = (FTC_FaceID)pfitemp->GetId();
}
}
}
bool FreeTypeFontInfo::EmbeddedBmpExist(int px)
{
if (px>=256 || px<0)
return false;
if (m_ebmps[px]!=-1)
return !!m_ebmps[px];
CCriticalSectionLock __lock(CCriticalSectionLock::CS_MANAGER);
FTC_ImageTypeRec imgtype={(FTC_FaceID)m_id, px, px, FT_LOAD_DEFAULT}; //构造一个当前大小的imagetype
FT_Glyph temp_glyph=NULL;
FT_UInt gindex = FTC_CMapCache_Lookup(cmap_cache, (FTC_FaceID)m_id, -1, FT_UInt32(L'0')); //获得0的索引值
FTC_ImageCache_Lookup(image_cache, &imgtype, gindex, &temp_glyph, NULL);
if (temp_glyph && temp_glyph->format==FT_GLYPH_FORMAT_BITMAP) //如果可以读到0的点阵
m_ebmps[px]=1; //则该字号存在点阵
else
{
gindex = FTC_CMapCache_Lookup(cmap_cache, (FTC_FaceID)m_id, -1, FT_UInt32(L'')); //获得"的"的索引值
if (gindex)
FTC_ImageCache_Lookup(image_cache, &imgtype, gindex, &temp_glyph, NULL); //读取“的”的点阵
if (temp_glyph && temp_glyph->format==FT_GLYPH_FORMAT_BITMAP) //如果可以读到0的点阵
m_ebmps[px]=1; //则该字号存在点阵
else
m_ebmps[px]=0;
}
return !!m_ebmps[px];
}
FreeTypeFontCache* FreeTypeFontInfo::GetCache(FTC_ScalerRec& scaler, const LOGFONT& lf)
{
CCriticalSectionLock __lock(CCriticalSectionLock::CS_FONTCACHE);
if (AddIncrement() > m_nMaxSizes) { //先压缩
Compact();
}
int weight = lf.lfWeight;
weight = weight < FW_BOLD ? 0: 1/*FW_BOLD*/;
const bool italic = !!lf.lfItalic;
if (scaler.height>0xfff || scaler.width>0xfff/* || scaler.height<0 || scaler.width<0*/) //超大字体不渲染
return NULL;
FreeTypeFontCache* p = NULL;
UINT hash=getCacheHash(scaler.height, weight, italic, lf.lfWidth ? scaler.width : 0); //计算hash
CacheArray::iterator it=m_cache.find(hash); //寻找cache
if (it!=m_cache.end())//cache存在
{
p = it->second;
goto OK; //返回cache
}
p = new FreeTypeFontCache(/*scaler.height, weight, italic,*/ MruIncrement());
if (!p) {
return NULL;
}
if (m_cache[hash]=p) {
goto OK;
}
delete p;
return NULL;
OK:
Assert(p != NULL);
if (p && p->Activate()) {
DecIncrement(); //重复使用则减计数值
}
return p;
}
//FreeTypeFontEngine
void FreeTypeFontEngine::Compact()
{
CCriticalSectionLock __lock(CCriticalSectionLock::CS_FONTENG);
TRACE(_T("FreeTypeFontEngine::Compact: %d > %d\n"), m_mfontMap.size(), m_nMaxFaces);
ResetGCCounter();
//memset(m_arrFace, 0, sizeof(FT_Face)*m_nFaceCount); //超过最大face数了老的face会被ft释放掉所以需要全部重新获取
//FontListArray& arr = m_arrFontList;
//::Compact(arr.GetData(), arr.GetSize(), m_nMaxFaces);
}
BOOL FreeTypeFontEngine::RemoveFont(FreeTypeFontInfo* fontinfo)
{
CCriticalSectionLock __lock(CCriticalSectionLock::CS_FONTMAP);
{
FontMap::const_iterator iter=m_mfontMap.begin(); //遍历fontmap
while (iter!=m_mfontMap.end())
{
FreeTypeFontInfo* p = iter->second;
if (p==fontinfo)
m_mfontMap.erase(iter++); //删除引用
else
++iter;
}
}
{
FullNameMap::const_iterator iter=m_mfullMap.begin(); //遍历fullmap
while (iter!=m_mfullMap.end())
{
FreeTypeFontInfo* p = iter->second;
if (p==fontinfo)
m_mfullMap.erase(iter++); //删除引用
else
{
iter->second->UpdateFontSetting();
++iter;
}
}
}
delete fontinfo;
return true;
}
BOOL FreeTypeFontEngine::RemoveThisFont(FreeTypeFontInfo* fontinfo, LOGFONT* lg)
{
CCriticalSectionLock __lock(CCriticalSectionLock::CS_FONTMAP);
{
FontMap::const_iterator iter=m_mfontMap.find(myfont(lg->lfFaceName, CalcBoldWeight(lg->lfWeight), lg->lfItalic)); //遍历fontmap
if (iter!=m_mfontMap.end())
m_mfontMap.erase(iter); //删除引用
}
{
FullNameMap::const_iterator iter=m_mfullMap.find(fontinfo->GetFullName()); //遍历fullmap
if (iter!=m_mfullMap.end())
m_mfullMap.erase(iter); //删除引用
}
delete fontinfo;
return true;
}
BOOL FreeTypeFontEngine::RemoveFont(LPCWSTR FontName)
{
if (!FontName) return false;
LOGFONTW* fontarray = GetFontNameFromFile(FontName);
LOGFONTW* c_fontarray = fontarray; //记录原始指针
if (!fontarray) return false;
FTC_FaceID fid = NULL;
BOOL bIsFontLoaded, bIsFontFileLoaded = false;
COwnedCriticalSectionLock __lock2(2, COwnedCriticalSectionLock::OCS_DC); //获取所有权现在要处理DC禁止所有绘图函数访问
CCriticalSectionLock __lock(CCriticalSectionLock::CS_MANAGER);
while (*(char*)fontarray)
{
bIsFontLoaded = false;
FreeTypeFontInfo* result = FindFont(fontarray->lfFaceName, fontarray->lfWeight, !!fontarray->lfItalic, false, &bIsFontLoaded);
if (result)
{
fid = (FTC_FaceID)result->GetId();
if (bIsFontLoaded) //该字体已经被使用过
{
RemoveFont(result); //枚举字体信息全部删除
bIsFontFileLoaded = true; //设置字体文件也被使用过
}
else
RemoveThisFont(result, fontarray);
CCriticalSectionLock __lock(CCriticalSectionLock::CS_FONTENG);
FTC_Manager_RemoveFaceID(cache_man, fid);
m_mfontList[(int)fid-1]=NULL;
}
fontarray++;
}
free(c_fontarray); //利用原始指针释放
if (bIsFontFileLoaded) //若字体文件被使用过则需要清楚所有DC
{
CTLSDCArray::iterator iter = TLSDCArray.begin();
while (iter!=TLSDCArray.end())
{
((CBitmapCache*)*iter)->~CBitmapCache(); //清除掉所有使用中的DC
++iter;
}
}
return true;
}
static int FaceIDHolder = 0;
int GetFaceID(void)
{
return (int)InterlockedIncrement((LONG volatile*)&FaceIDHolder);
}
void ReleaseFaceID(void)
{
InterlockedDecrement((LONG volatile*)&FaceIDHolder);
}
FreeTypeFontInfo* FreeTypeFontEngine::AddFont(void* lpparams)
{
FREETYPE_PARAMS* params = (FREETYPE_PARAMS*)lpparams;
CCriticalSectionLock __lock(CCriticalSectionLock::CS_FONTENG);
const LOGFONT& lplf = *params->lplf;
if(!*lplf.lfFaceName || _tcslen(lplf.lfFaceName) == 0)
return NULL;
const CGdippSettings* pSettings = CGdippSettings::GetInstance();
//const CFontSettings& fs = pSettings->FindIndividual(params->strFamilyName.c_str());
FreeTypeFontInfo* pfi = new FreeTypeFontInfo(/*m_mfullMap.size() + 1*/GetFaceID(), lplf.lfFaceName, lplf.lfWeight, !!lplf.lfItalic, MruIncrement(), params->strFullName, params->strFamilyName);
if (!pfi)
return NULL;
if (pfi->GetFullName().size()==0) //点阵字
{
delete pfi;
ReleaseFaceID();
return NULL;
}
/*
TCHAR buff[255]={0};
if (params->strFamilyName.length()==8)
{
wsprintf(buff, L"Adding familiyname \"%s\" fullname \"%s\" weight %d\n\result: \"%s\"\n", params->strFamilyName.c_str(), params->strFullName.c_str(),
params->lplf->lfWeight, pfi->GetFullName().c_str());
Log(buff);
}*/
FullNameMap::const_iterator it = m_mfullMap.find(pfi->GetFullName());
if (it!=m_mfullMap.end()) //是已经存在的字体了,原因是字体替换使两种名字指向一个字体
{
delete pfi; //删除刚才创建的字体
ReleaseFaceID();
pfi = it->second;//指向原字体
}
else
{
m_mfullMap[pfi->GetFullName()]=pfi; //不存在添加到map表
m_mfontList.push_back(pfi);
}
if (pfi->GetFullName()!=params->strFullName) //如果目标字体的真实名称和需要的名称不一样,说明是字体替换
{
pfi->AddRef(); //增加引用计数
m_mfullMap[params->strFullName] = pfi; //双重引用,指向同一个字体
}
//bool ret = !!arr.Add(pfi);
//weight = weight < FW_BOLD ? 0: FW_BOLD;
myfont font(lplf.lfFaceName, lplf.lfWeight, !!params->otm->otmTextMetrics.tmItalic);
/*
FontMap::const_iterator it = m_mfontMap.find(font);
if (it!=m_mfontMap.end())
{
it->second->Release();
}*/
m_mfontMap[font]=pfi;
/*
if (!ret) {
delete pfi;
return NULL;
}*/
#ifdef _DEBUG
{
const CFontSettings& fs = pfi->GetFontSettings();
TRACE(_T("AddFont: %s, %d, %d, %d, %d, %d, %d\n"), pfi->GetName(),
fs.GetParam(0), fs.GetParam(1), fs.GetParam(2), fs.GetParam(3), fs.GetParam(4), fs.GetParam(5));
}
#endif
return pfi;
}
FreeTypeFontInfo* FreeTypeFontEngine::AddFont(LPCTSTR lpFaceName, int weight, bool italic, BOOL* bIsFontLoaded)
{
CCriticalSectionLock __lock(CCriticalSectionLock::CS_FONTENG);
if(lpFaceName == NULL || _tcslen(lpFaceName) == 0/* || FontExists(lpFaceName, weight, italic)*/)
return NULL;
//FontListArray& arr = m_arrFontList;
const CGdippSettings* pSettings = CGdippSettings::GetInstance();
//const CFontSettings& fs = pSettings->FindIndividual(lpFaceName);
wstring dumy;
//dumy.clear();
FreeTypeFontInfo* pfi = new FreeTypeFontInfo(/*m_mfullMap.size() + 1*/GetFaceID(), lpFaceName, weight, italic, MruIncrement(), dumy, dumy);
if (!pfi)
return NULL;
if (pfi->GetFullName().size()==0) //点阵字
{
delete pfi;
ReleaseFaceID();
return NULL;
}
FullNameMap::const_iterator it = m_mfullMap.find(pfi->GetFullName()); //是否在主map表中存在了
if (it!=m_mfullMap.end()) //已经存在
{
delete pfi; //删除创建出来的字体
ReleaseFaceID();
pfi = it->second; //指向已经存在的字体
if (bIsFontLoaded)
*bIsFontLoaded = true;
//pfi->AddRef();
}
else
{
m_mfullMap[pfi->GetFullName()]=pfi; //不存在添加到map表
m_mfontList.push_back(pfi);
if (bIsFontLoaded)
*bIsFontLoaded = false;
}
//bool ret = !!arr.Add(pfi);
//weight = weight < FW_BOLD ? 0: FW_BOLD;
myfont font(lpFaceName, weight, italic);
m_mfontMap[font]=pfi; //添加在次要map表
/*
if (!ret) {
delete pfi;
return NULL;
}*/
#ifdef _DEBUG
{
const CFontSettings& fs = pfi->GetFontSettings();
TRACE(_T("AddFont: %s, %d, %d, %d, %d, %d, %d\n"), pfi->GetName(),
fs.GetParam(0), fs.GetParam(1), fs.GetParam(2), fs.GetParam(3), fs.GetParam(4), fs.GetParam(5));
}
#endif
return pfi;
}
int FreeTypeFontEngine::GetFontIdByName(LPCTSTR lpFaceName, int weight, bool italic)
{
const FreeTypeFontInfo* pfi = FindFont(lpFaceName, weight, italic);
return pfi ? pfi->GetId() : 0;
}
/*
LPCTSTR FreeTypeFontEngine::GetFontById(int faceid, int& weight, bool& italic)
{
CCriticalSectionLock __lock;
FreeTypeFontInfo** pp = m_arrFontList.Begin();
FreeTypeFontInfo** end = m_arrFontList.End();
for(; pp != end; ++pp) {
FreeTypeFontInfo* p = *pp;
if (p->GetId() == faceid) {
p->SetMruCounter(this);
weight = p->GetWeight();
italic = p->IsItalic();
return p->GetName();
}
}
return NULL;
}
*/
FreeTypeFontInfo* FreeTypeFontEngine::FindFont(void* lpparams)
{
FREETYPE_PARAMS* params = (FREETYPE_PARAMS*)lpparams;
CCriticalSectionLock __lock(CCriticalSectionLock::CS_FONTMAP);
FullNameMap::const_iterator iter=m_mfullMap.find(params->strFullName);
if (iter!=m_mfullMap.end())
{
FreeTypeFontInfo* p = iter->second;
if (p->GetFullName()!=params->strFullName) //属于替换字体
return FindFont(params->lplf->lfFaceName, params->lplf->lfWeight, !!params->lplf->lfItalic);
p->SetMruCounter(this);
return p;
}
//m_bAddOnFind = true;
return AddFont(params);
}
FreeTypeFontInfo* FreeTypeFontEngine::FindFont(LPCTSTR lpFaceName, int weight, bool italic, bool AddOnFind, BOOL* bIsFontLoaded)
{
/*
if (m_bAddOnFind)
{
m_bAddOnFind = false;
return NULL;
}*/
CCriticalSectionLock __lock(CCriticalSectionLock::CS_FONTMAP);
weight = CalcBoldWeight(weight);
myfont font(lpFaceName, weight, italic);
FontMap::const_iterator iter=m_mfontMap.find(font);
if (iter!=m_mfontMap.end())
{
FreeTypeFontInfo* p = iter->second;
p->SetMruCounter(this);
/*
TCHAR buff[255]={0};
if (wcslen(lpFaceName)==8)
{
wsprintf(buff, L"Finding familiyname \"%s\" weight %d\n\tFound: \"%s\"\n", lpFaceName,
weight, p->GetFullName().c_str());
Log(buff);
}*/
if (bIsFontLoaded)
*bIsFontLoaded = true;
return p;
}
//m_bAddOnFind = true;
return AddFont(lpFaceName, weight, italic, bIsFontLoaded);
}
FreeTypeFontInfo* FreeTypeFontEngine::FindFont(int faceid)
{
CCriticalSectionLock __lock(CCriticalSectionLock::CS_FONTMAP);
if (faceid>m_mfontList.size())
return NULL;
else
return m_mfontList[faceid-1]; //存在bug
/*
FullNameMap::const_iterator iter=m_mfullMap.begin();
for(; iter != m_mfullMap.end(); ++iter) {
FreeTypeFontInfo* p = iter->second;
if (p->GetId() == faceid) {
p->SetMruCounter(this);
return p;
}
}
return NULL;*/
}
//FreeTypeSysFontData
// http://kikyou.info/diary/?200510#i10 を参考にした
#include <freetype/tttables.h> // FT_TRUETYPE_TABLES_H
#include <mmsystem.h> //mmioFOURCC
#define TVP_TT_TABLE_ttcf mmioFOURCC('t', 't', 'c', 'f')
#define TVP_TT_TABLE_name mmioFOURCC('n', 'a', 'm', 'e')
// Windowsに登録されているフォントのバイナリデータを名称から取得
FreeTypeSysFontData* FreeTypeSysFontData::CreateInstance(LPCTSTR name, int weight, bool italic)
{
FreeTypeSysFontData* pData = new FreeTypeSysFontData;
if (!pData) {
return NULL;
}
if (!pData->Init(name, weight, italic)) {
delete pData;
return NULL;
}
return pData;
}
bool FreeTypeSysFontData::Init(LPCTSTR name, int weight, bool italic)
{
const CGdippSettings* pSettings = CGdippSettings::GetInstance();
void* pNameFromGDI = NULL; // Windows から取得した name タグの内容
void* pNameFromFreeType = NULL; // FreeType から取得した name タグの内容
HFONT hf = NULL;
DWORD cbNameTable;
DWORD cbFontData;
int index;
DWORD buf;
FT_StreamRec& fsr = m_ftStream;
m_name.assign(name);
m_hdc = CreateCompatibleDC(NULL);
if(m_hdc == NULL) {
return false;
}
// 名前以外適当
if (pSettings->FontSubstitutes() < SETTING_FONTSUBSTITUTE_ALL)
{
hf = CreateFont(
12, 0, 0, 0, weight,
italic, FALSE, FALSE,
DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS,
FONT_MAGIC_NUMBER,
DEFAULT_QUALITY,
DEFAULT_PITCH | FF_DONTCARE,
name);
}
else
hf = CreateFont(
12, 0, 0, 0, weight,
italic, FALSE, FALSE,
DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
DEFAULT_PITCH | FF_DONTCARE,
name);
if(hf == NULL){
return false;
}
m_hOldFont = SelectFont(m_hdc, hf);
// フォントデータが得られそうかチェック
cbNameTable = ORIG_GetFontData(m_hdc, TVP_TT_TABLE_name, 0, NULL, 0);
if(cbNameTable == GDI_ERROR){
goto ERROR_Init;
}
pNameFromGDI = malloc(cbNameTable);
if (!pNameFromGDI) {
goto ERROR_Init;
}
pNameFromFreeType = malloc(cbNameTable);
if (!pNameFromFreeType) {
goto ERROR_Init;
}
//- name タグの内容をメモリに読み込む
if(ORIG_GetFontData(m_hdc, TVP_TT_TABLE_name, 0, pNameFromGDI, cbNameTable) == GDI_ERROR){
goto ERROR_Init;
}
// フォントサイズ取得処理
cbFontData = ORIG_GetFontData(m_hdc, TVP_TT_TABLE_ttcf, 0, &buf, 1);
if(cbFontData == 1){
// TTC ファイルだと思われる
cbFontData = ORIG_GetFontData(m_hdc, TVP_TT_TABLE_ttcf, 0, NULL, 0);
m_isTTC = true;
}
else{
cbFontData = ORIG_GetFontData(m_hdc, 0, 0, NULL, 0);
}
if(cbFontData == GDI_ERROR){
// エラー; GetFontData では扱えなかった
goto ERROR_Init;
}
if (pSettings->UseMapping()) {
HANDLE hmap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE | SEC_COMMIT | SEC_NOCACHE, 0, cbFontData, NULL);
if (!hmap) {
goto ERROR_Init;
}
m_pMapping = MapViewOfFile(hmap, FILE_MAP_ALL_ACCESS, 0, 0, cbFontData);
m_dwSize = cbFontData;
CloseHandle(hmap);
if (m_pMapping) {
ORIG_GetFontData(m_hdc, m_isTTC ? TVP_TT_TABLE_ttcf : 0, 0, m_pMapping, cbFontData);
}
}
// FT_StreamRec の各フィールドを埋める
fsr.base = 0;
fsr.size = cbFontData;
fsr.pos = 0;
fsr.descriptor.pointer = this;
fsr.pathname.pointer = NULL;
fsr.read = IoFunc;
fsr.close = CloseFunc;
index = 0;
m_locked = true;
if(!OpenFaceByIndex(index)){
goto ERROR_Init;
}
for(;;) {
// FreeType から、name タグのサイズを取得する
FT_ULong length = 0;
FT_Error err = FT_Load_Sfnt_Table(m_ftFace, TTAG_name, 0, NULL, &length);
if(err){
goto ERROR_Init;
}
// FreeType から得た name タグの長さを Windows から得た長さと比較
if(length == cbNameTable){
// FreeType から name タグを取得
err = FT_Load_Sfnt_Table(m_ftFace, TTAG_name, 0, (unsigned char*)pNameFromFreeType, &length);
if(err){
goto ERROR_Init;
}
// FreeType から読み込んだ name タグの内容と、Windows から読み込んだ
// name タグの内容を比較する。
// 一致していればその index のフォントを使う。
if(!memcmp(pNameFromGDI, pNameFromFreeType, cbNameTable)){
// 一致した
// face は開いたまま
break; // ループを抜ける
}
}
// 一致しなかった
// インデックスを一つ増やし、その face を開く
index ++;
if(!OpenFaceByIndex(index)){
// 一致する face がないまま インデックスが範囲を超えたと見られる
// index を 0 に設定してその index を開き、ループを抜ける
index = 0;
if(!OpenFaceByIndex(index)){
goto ERROR_Init;
}
break;
}
}
free(pNameFromGDI);
free(pNameFromFreeType);
m_locked = false;
return true;
ERROR_Init:
m_locked = false;
if (hf) {
SelectFont(m_hdc, m_hOldFont);
DeleteFont(hf);
m_hOldFont = NULL;
}
free(pNameFromGDI);
free(pNameFromFreeType);
return false;
}
unsigned long FreeTypeSysFontData::IoFunc(
FT_Stream stream,
unsigned long offset,
unsigned char* buffer,
unsigned long count )
{
if(count == 0){
return 0;
}
FreeTypeSysFontData * pThis = reinterpret_cast<FreeTypeSysFontData*>(stream->descriptor.pointer);
Assert(pThis != NULL);
DWORD result = 0;
if (pThis->m_pMapping) {
result = Min(pThis->m_dwSize - offset, count);
memcpy(buffer, (const BYTE*)pThis->m_pMapping + offset, result);
} else {
result = ::GetFontData(pThis->m_hdc, pThis->m_isTTC ? TVP_TT_TABLE_ttcf : 0, offset, buffer, count);
if(result == GDI_ERROR) {
// エラー
return 0;
}
}
return result;
}
void FreeTypeSysFontData::CloseFunc(FT_Stream stream)
{
FreeTypeSysFontData * pThis = reinterpret_cast<FreeTypeSysFontData*>(stream->descriptor.pointer);
Assert(pThis != NULL);
if(!pThis->m_locked)
delete pThis;
}
bool FreeTypeSysFontData::OpenFaceByIndex(int index)
{
if(m_ftFace) {
FT_Done_Face(m_ftFace);
m_ftFace = NULL;
}
FT_Open_Args args = { 0 };
args.flags = FT_OPEN_STREAM;
args.stream = &m_ftStream;
// FreeType で扱えるか?
FT_Error ftErrCode = FT_Open_Face(freetype_library, &args, index, &m_ftFace);
#ifdef DEBUG
if (ftErrCode!=0)
TRACE(L"Open face failed, error = %d\n", ftErrCode);
#endif
return (ftErrCode == 0);
}