2016-05-30 17:12:15 +08:00
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <ft2build.h>
|
|
|
|
|
#include <freetype/freetype.h> /* FT_FREETYPE_H */
|
|
|
|
|
#include <freetype/ftcache.h> /* FT_CACHE_H */
|
|
|
|
|
#include <freetype/tttables.h>
|
|
|
|
|
#include <freetype/tttags.h> // FT_TRUETYPE_TAGS_H
|
|
|
|
|
#include <freetype/ftoutln.h>
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include "ftref.h"
|
|
|
|
|
#include <math.h>
|
|
|
|
|
#include "undocAPI.h"
|
|
|
|
|
|
|
|
|
|
class FreeTypeFontEngine;
|
|
|
|
|
extern FreeTypeFontEngine* g_pFTEngine;
|
|
|
|
|
extern BOOL g_ccbCache;
|
|
|
|
|
extern BOOL g_ccbIndividual;
|
|
|
|
|
extern FTC_Manager cache_man;
|
|
|
|
|
|
|
|
|
|
typedef set<CBitmapCache*> CTLSDCArray;
|
|
|
|
|
extern CTLSDCArray TLSDCArray;
|
|
|
|
|
|
|
|
|
|
LOGFONTW* GetFontNameFromFile(LPCTSTR Filename);
|
2020-12-06 18:38:08 +08:00
|
|
|
|
bool GetFontLocalName(TCHAR* pszFontName, __out TCHAR* pszNameOut); //获得字体的本地化名称
|
2016-05-30 17:12:15 +08:00
|
|
|
|
|
|
|
|
|
struct CFontSetCache
|
|
|
|
|
{
|
|
|
|
|
const CFontSettings** fontsetlist;
|
|
|
|
|
int fontsetsize;
|
|
|
|
|
CFontSetCache()
|
|
|
|
|
:fontsetsize(0)
|
|
|
|
|
{
|
|
|
|
|
fontsetsize=64;
|
|
|
|
|
fontsetlist = (const CFontSettings**)malloc(fontsetsize * sizeof(void*));
|
|
|
|
|
}
|
|
|
|
|
~CFontSetCache()
|
|
|
|
|
{
|
|
|
|
|
free(fontsetlist);
|
|
|
|
|
}
|
|
|
|
|
void Set(FTC_FaceID faceid, const CFontSettings& fset)
|
|
|
|
|
{
|
|
|
|
|
while ((INT_PTR)faceid>=fontsetsize)
|
|
|
|
|
{
|
|
|
|
|
fontsetsize+=64;
|
|
|
|
|
fontsetlist = (const CFontSettings**)realloc(fontsetlist, fontsetsize);
|
|
|
|
|
}
|
|
|
|
|
fontsetlist[(INT_PTR)faceid]=&fset;
|
|
|
|
|
}
|
|
|
|
|
const CFontSettings*& Get(FTC_FaceID faceid) const
|
|
|
|
|
{
|
|
|
|
|
return fontsetlist[(INT_PTR)faceid];
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct myfont
|
|
|
|
|
{
|
|
|
|
|
wstring name;
|
|
|
|
|
int hash;
|
2019-07-09 22:10:00 +08:00
|
|
|
|
bool operator < (const myfont& mf) const {
|
2016-05-30 17:12:15 +08:00
|
|
|
|
return name==mf.name? hash<mf.hash: name<mf.name;
|
|
|
|
|
}
|
|
|
|
|
public:
|
|
|
|
|
myfont(LPCWSTR lpFaceName, int nweight, int nitalic):
|
|
|
|
|
name(lpFaceName),hash((nitalic<<31) | nweight)
|
|
|
|
|
{}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum FT_EngineConstants {
|
|
|
|
|
FT_MAX_CHARS = 65536,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
2020-12-06 18:38:08 +08:00
|
|
|
|
FreeTypeに文字幅、太字、斜体をキャッシュする機構が無いのでそれらを補う
|
2016-05-30 17:12:15 +08:00
|
|
|
|
|
2020-12-06 18:38:08 +08:00
|
|
|
|
1. まずDllMain(DLL_PROCESS_ATTACH)でFreeTypeFontEngineのインスタンスが生成される。
|
|
|
|
|
(順番はCGdiPPSettings→FontLInit(FreeType)→FreeTypeFontEngine→フック)
|
|
|
|
|
ForceChangeFontもここで処理する。
|
2016-05-30 17:12:15 +08:00
|
|
|
|
|
2020-12-06 18:38:08 +08:00
|
|
|
|
2. CreateFontでFreeTypeFontEngine::AddFontが呼び出され、FreeTypeFontInfoと
|
|
|
|
|
フォント名を結びつける。
|
|
|
|
|
ついでにFreeTypeFontInfoはIndividualの設定をコピーして持つ。
|
2016-05-30 17:12:15 +08:00
|
|
|
|
|
2020-12-06 18:38:08 +08:00
|
|
|
|
3. ExtTextOutやGetTextExtentなどからFreeTypePrepare関数が呼び出されると
|
|
|
|
|
さらに内部でFreeTypeFontInfo::GetCacheが呼び出され、フォントサイズなどから
|
|
|
|
|
FreeTypeFontCacheを得る。無ければ生成する。
|
|
|
|
|
FreeTypeFontCacheは内部にFreeTypeCharDataのテーブル(UCS2なので2^16個)を
|
|
|
|
|
持っていて、FreeTypeCharDataには文字毎にキャッシュデータを保管する。
|
2016-05-30 17:12:15 +08:00
|
|
|
|
|
2020-12-06 18:38:08 +08:00
|
|
|
|
4. FreeTypeFontCacheから、文字またはグリフ番号を元にFreeTypeCharDataを得る。
|
|
|
|
|
キャッシュがあれば(メモリ中に残っていれば)、MRUカウンタをセットする。
|
|
|
|
|
無い場合は一旦スルーし、後でAddCharDataでキャッシュを追加する。
|
2016-05-30 17:12:15 +08:00
|
|
|
|
|
2020-12-06 18:38:08 +08:00
|
|
|
|
5. 追加しまくるとメモリを喰らうので、追加が一定数(FREETYPE_REQCOUNTMAX)を超えると
|
|
|
|
|
GCモドキで最近参照されたキャッシュデータをFREETYPE_GC_COUNTER個だけ残し、
|
|
|
|
|
それ以外のデータ(FreeTypeCharData)は開放される。
|
|
|
|
|
この2つの定数はiniで設定変更できた方がいいような気もする。
|
2016-05-30 17:12:15 +08:00
|
|
|
|
|
2020-12-06 18:38:08 +08:00
|
|
|
|
6. 最後に、DllMain(DLL_PROCESS_DETACH)でFreeTypeFontEngineのインスタンスが破棄され、
|
|
|
|
|
全てのキャッシュメモリが開放される。
|
2016-05-30 17:12:15 +08:00
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
class FreeTypeGCCounter
|
|
|
|
|
{
|
|
|
|
|
private:
|
2020-12-06 18:38:08 +08:00
|
|
|
|
int m_addcount; //追加用
|
|
|
|
|
int m_mrucount; //MRU用
|
2016-05-30 17:12:15 +08:00
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
FreeTypeGCCounter()
|
|
|
|
|
: m_addcount(0), m_mrucount(0)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
int AddIncrement() { return ++m_addcount; }
|
|
|
|
|
int DecIncrement() { return --m_addcount; }
|
|
|
|
|
int MruIncrement() { return ++m_mrucount; }
|
|
|
|
|
|
|
|
|
|
void ResetGCCounter()
|
|
|
|
|
{
|
|
|
|
|
m_mrucount = 0;
|
|
|
|
|
m_addcount = 0;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class FreeTypeMruCounter
|
|
|
|
|
{
|
|
|
|
|
private:
|
2020-12-06 18:38:08 +08:00
|
|
|
|
int m_mrucounter; //GC用
|
2016-05-30 17:12:15 +08:00
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
FreeTypeMruCounter(int n)
|
|
|
|
|
: m_mrucounter(n)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-06 18:38:08 +08:00
|
|
|
|
//GC用MRUカウンタ
|
2016-05-30 17:12:15 +08:00
|
|
|
|
int GetMruCounter() const { return m_mrucounter; }
|
|
|
|
|
void ResetMruCounter() { m_mrucounter = 0; }
|
|
|
|
|
void SetMruCounter(FreeTypeGCCounter* p) { m_mrucounter = p->MruIncrement(); }
|
|
|
|
|
};
|
|
|
|
|
|
2020-12-06 18:38:08 +08:00
|
|
|
|
//文字幅、(glyph index)、FT_BitmapGlyph(太字、斜体のみ)をキャッシュする
|
2016-05-30 17:12:15 +08:00
|
|
|
|
class FreeTypeCharData : public FreeTypeMruCounter
|
|
|
|
|
{
|
|
|
|
|
private:
|
|
|
|
|
typedef CValArray<FreeTypeCharData**> CharDataArray;
|
2020-12-06 18:38:08 +08:00
|
|
|
|
CharDataArray m_arrSelfChar; //自分自身の保存元(Char)
|
2016-05-30 17:12:15 +08:00
|
|
|
|
FreeTypeCharData** m_ppSelfGlyph; //(Glyph)
|
2020-12-06 18:38:08 +08:00
|
|
|
|
UINT m_glyphindex; //グリフ番号
|
|
|
|
|
int m_width; //文字幅
|
|
|
|
|
int m_gdiWidth; //使用GetCharWidth获得的GDI宽度
|
|
|
|
|
FT_Referenced_BitmapGlyph m_glyph; //カラー用
|
|
|
|
|
FT_Referenced_BitmapGlyph m_glyphMono; //モノクロ用
|
|
|
|
|
int m_bmpSize; //ビットマップサイズ
|
|
|
|
|
int m_bmpMonoSize; // 〃
|
2016-05-30 17:12:15 +08:00
|
|
|
|
int m_AAMode;
|
2020-12-06 18:38:08 +08:00
|
|
|
|
// LONG m_refcounter; //参照カウンタ
|
2016-05-30 17:12:15 +08:00
|
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
2020-12-06 18:38:08 +08:00
|
|
|
|
WCHAR m_wch; //UCS2文字
|
2016-05-30 17:12:15 +08:00
|
|
|
|
#endif
|
|
|
|
|
NOCOPY(FreeTypeCharData);
|
|
|
|
|
|
2020-12-06 18:38:08 +08:00
|
|
|
|
//FT_Bitmap::bufferのサイズを返す
|
2016-05-30 17:12:15 +08:00
|
|
|
|
static inline int FT_Bitmap_CalcSize(FT_BitmapGlyph gl)
|
|
|
|
|
{
|
|
|
|
|
return gl->bitmap.pitch * gl->bitmap.rows;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
FreeTypeCharData(FreeTypeCharData** ppCh, FreeTypeCharData** ppGl, WCHAR wch, UINT glyphindex, int width, int mru, int gdiWidth, int AAMode);
|
|
|
|
|
~FreeTypeCharData();
|
|
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
WCHAR GetChar() const { return m_wch; }
|
|
|
|
|
#else
|
|
|
|
|
WCHAR GetChar() const { return L'?'; }
|
|
|
|
|
#endif
|
|
|
|
|
UINT GetGlyphIndex() const { return m_glyphindex; }
|
|
|
|
|
int GetWidth() const { return m_width; }
|
|
|
|
|
void SetWidth(int width) { m_width = width; }
|
|
|
|
|
void SetGDIWidth(int width) { m_gdiWidth = width; }
|
|
|
|
|
int GetGDIWidth() const {return m_gdiWidth; }
|
|
|
|
|
int GetAAMode() const {return m_AAMode; }
|
|
|
|
|
void AddChar(FreeTypeCharData** ppCh)
|
|
|
|
|
{
|
|
|
|
|
if (ppCh)
|
|
|
|
|
m_arrSelfChar.Add(ppCh);
|
|
|
|
|
}
|
|
|
|
|
FT_Referenced_BitmapGlyph GetGlyph(FT_Render_Mode render_mode) const
|
|
|
|
|
{
|
|
|
|
|
return (render_mode == FT_RENDER_MODE_MONO) ? m_glyphMono : m_glyph;
|
|
|
|
|
}
|
|
|
|
|
void SetGlyph(FT_Render_Mode render_mode, FT_Referenced_BitmapGlyph glyph);
|
|
|
|
|
|
|
|
|
|
void Erase()
|
|
|
|
|
{
|
|
|
|
|
//delete this;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
static INT_PTR NULL_INT = NULL;
|
|
|
|
|
class FreeTypeFontCache : public FreeTypeMruCounter, public FreeTypeGCCounter
|
|
|
|
|
{
|
|
|
|
|
typedef map<int, FreeTypeCharData*> GlyphCache;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
int m_px;
|
|
|
|
|
int m_weight;
|
|
|
|
|
bool m_italic;
|
|
|
|
|
bool m_active;
|
|
|
|
|
TEXTMETRIC m_tm;
|
|
|
|
|
|
2020-12-06 18:38:08 +08:00
|
|
|
|
//4×65536×2=512KBぐらいたかが知れてるので固定配列で問題無し
|
2016-05-30 17:12:15 +08:00
|
|
|
|
#ifdef _USE_ARRAY
|
|
|
|
|
FreeTypeCharData* m_chars[FT_MAX_CHARS];
|
|
|
|
|
FreeTypeCharData* m_glyphs[FT_MAX_CHARS];
|
|
|
|
|
#else
|
|
|
|
|
GlyphCache m_GlyphCache;
|
|
|
|
|
#endif
|
|
|
|
|
NOCOPY(FreeTypeFontCache);
|
|
|
|
|
void Compact();
|
|
|
|
|
|
|
|
|
|
FreeTypeCharData** _GetChar(WCHAR wch)
|
|
|
|
|
{
|
|
|
|
|
#ifdef _USE_ARRAY
|
|
|
|
|
return m_chars + wch;
|
|
|
|
|
#else
|
|
|
|
|
GlyphCache::iterator it=m_GlyphCache.find(wch);
|
|
|
|
|
return it==m_GlyphCache.end()? reinterpret_cast<FreeTypeCharData**>(&NULL_INT): &(it->second);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
FreeTypeCharData** _GetGlyph(UINT glyph)
|
|
|
|
|
{
|
|
|
|
|
#ifdef _USE_ARRAY
|
|
|
|
|
return m_glyphs + glyph;
|
|
|
|
|
#else
|
|
|
|
|
GlyphCache::iterator it=m_GlyphCache.find(-(int)glyph);
|
|
|
|
|
return it == m_GlyphCache.end() ? reinterpret_cast<FreeTypeCharData**>(&NULL_INT) : &(it->second);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
FreeTypeFontCache(/*int px, int weight, bool italic, */int mru);
|
|
|
|
|
~FreeTypeFontCache();
|
|
|
|
|
|
|
|
|
|
const TEXTMETRIC& GetTextMetric(HDC hdc)
|
|
|
|
|
{
|
|
|
|
|
if (m_tm.tmHeight == 0) {
|
|
|
|
|
::GetTextMetrics(hdc, &m_tm);
|
|
|
|
|
}
|
|
|
|
|
return m_tm;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Equals(int px, int weight, bool italic) const
|
|
|
|
|
{
|
|
|
|
|
return (m_px == px && m_weight == weight && m_italic == italic);
|
|
|
|
|
}
|
|
|
|
|
FreeTypeCharData* FindChar(WCHAR wch)
|
|
|
|
|
{
|
|
|
|
|
/*if (!g_ccbCache) return NULL;*/
|
|
|
|
|
FreeTypeCharData* p = *_GetChar(wch);
|
|
|
|
|
if(p) {
|
|
|
|
|
p->SetMruCounter(this);
|
|
|
|
|
}
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FreeTypeCharData* FindGlyphIndex(UINT glyph)
|
|
|
|
|
{
|
|
|
|
|
/*if (!g_ccbCache) return NULL;*/
|
|
|
|
|
FreeTypeCharData* p = (glyph & 0xffff0000) ? NULL : *_GetGlyph(glyph);
|
|
|
|
|
if(p) {
|
|
|
|
|
p->SetMruCounter(this);
|
|
|
|
|
}
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Activate()
|
|
|
|
|
{
|
|
|
|
|
if (!m_active) {
|
|
|
|
|
m_active = true;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Erase();
|
|
|
|
|
void Deactive() { m_active = false; };
|
|
|
|
|
void AddCharData(WCHAR wch, UINT glyphindex, int width, int gdiWidth, FT_Referenced_BitmapGlyph glyph, FT_Render_Mode render_mode, int AAMode);
|
|
|
|
|
void AddGlyphData(UINT glyphindex, int width, int gdiWidth, FT_Referenced_BitmapGlyph glyph, FT_Render_Mode render_mode, int AAMode);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2020-12-06 18:38:08 +08:00
|
|
|
|
// フォント名とFaceID(intを使うことにする)
|
2016-05-30 17:12:15 +08:00
|
|
|
|
//extern CFontSetCache g_fsetcache;
|
|
|
|
|
extern CHashedStringList FontNameCache;
|
|
|
|
|
class FreeTypeFontInfo : public FreeTypeMruCounter, public FreeTypeGCCounter
|
|
|
|
|
{
|
|
|
|
|
private:
|
|
|
|
|
INT_PTR m_id;
|
|
|
|
|
int m_weight;
|
|
|
|
|
bool m_italic;
|
|
|
|
|
char m_hashinting;
|
|
|
|
|
int m_ftWeight;
|
2018-04-13 14:05:08 +08:00
|
|
|
|
int m_os2Weight;
|
2016-05-30 17:12:15 +08:00
|
|
|
|
int m_nMaxSizes;
|
|
|
|
|
int m_nFontFamily;
|
|
|
|
|
HFONT m_ggoFont;
|
|
|
|
|
TT_OS2* m_OS2Table;
|
|
|
|
|
char m_ebmps[256];
|
|
|
|
|
LONG volatile count;
|
|
|
|
|
CFontSettings m_set;
|
|
|
|
|
StringHashFont m_hash;
|
|
|
|
|
wstring m_fullname, m_familyname;
|
|
|
|
|
typedef map<UINT, FreeTypeFontCache*> CacheArray;
|
|
|
|
|
CacheArray m_cache;
|
2020-12-06 17:00:05 +08:00
|
|
|
|
//快速链接
|
2016-05-30 17:12:15 +08:00
|
|
|
|
FTC_FaceID face_id_link[CFontLinkInfo::FONTMAX * 2 + 1];
|
|
|
|
|
HFONT ggo_link[CFontLinkInfo::FONTMAX * 2 + 1];
|
|
|
|
|
bool m_linkinited;
|
|
|
|
|
int m_linknum;
|
|
|
|
|
FTC_FaceID m_SimSunID;
|
|
|
|
|
NOCOPY(FreeTypeFontInfo);
|
|
|
|
|
void Compact();
|
|
|
|
|
void Createlink();
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
void AddRef() {InterlockedIncrement(&count);};
|
|
|
|
|
void Release() {
|
|
|
|
|
if (InterlockedDecrement(&count)==0)
|
|
|
|
|
delete this;
|
|
|
|
|
}
|
|
|
|
|
TT_OS2* GetOS2Table()
|
|
|
|
|
{
|
|
|
|
|
if (!m_OS2Table)
|
|
|
|
|
{
|
|
|
|
|
TT_OS2 * os2_table = NULL;
|
|
|
|
|
FT_Face freetype_face;
|
|
|
|
|
CCriticalSectionLock __lock(CCriticalSectionLock::CS_MANAGER);
|
|
|
|
|
if (FTC_Manager_LookupFace(cache_man, (FTC_FaceID)m_id, &freetype_face))
|
|
|
|
|
return NULL;
|
|
|
|
|
os2_table = (TT_OS2*) FT_Get_Sfnt_Table(freetype_face, ft_sfnt_os2);
|
|
|
|
|
if (!os2_table) return NULL;
|
|
|
|
|
m_OS2Table = new TT_OS2;
|
|
|
|
|
memcpy(m_OS2Table, os2_table, sizeof(TT_OS2));
|
|
|
|
|
}
|
|
|
|
|
return m_OS2Table;
|
|
|
|
|
}
|
|
|
|
|
BOOL FontHasHinting()
|
|
|
|
|
{
|
|
|
|
|
if (m_hashinting==3)
|
|
|
|
|
{
|
|
|
|
|
FT_Face freetype_face;
|
|
|
|
|
CCriticalSectionLock __lock(CCriticalSectionLock::CS_MANAGER);
|
2020-12-06 18:38:08 +08:00
|
|
|
|
if (FTC_Manager_LookupFace(cache_man, (FTC_FaceID)m_id, &freetype_face)) //查询ft face
|
2016-05-30 17:12:15 +08:00
|
|
|
|
{
|
|
|
|
|
m_hashinting = false;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
FT_ULong length = 0;
|
2020-12-06 18:38:08 +08:00
|
|
|
|
FT_Error err = FT_Load_Sfnt_Table(freetype_face, TTAG_fpgm, 0, NULL, &length); //获取fpgm表长度
|
|
|
|
|
if (!err && length>50) //成功读取表,并且长度较长
|
|
|
|
|
m_hashinting = true; //字体存在hinting
|
2016-05-30 17:12:15 +08:00
|
|
|
|
else
|
|
|
|
|
m_hashinting = false;
|
|
|
|
|
}
|
|
|
|
|
return m_hashinting;
|
|
|
|
|
}
|
|
|
|
|
wstring GetFullName() {return m_fullname;};
|
|
|
|
|
bool m_isSimSun;
|
|
|
|
|
bool IsPixel;
|
2020-12-06 18:38:08 +08:00
|
|
|
|
UINT getCacheHash(int px, int weight, bool italic, int width) {return ((px<<20)|(width<<8)|(weight<<1)|(int)italic); }; //计算一个hash值来定位cache
|
2016-05-30 17:12:15 +08:00
|
|
|
|
FreeTypeFontInfo(int n, LPCTSTR name, int weight, bool italic, int mru, wstring fullname, wstring familyname)
|
2016-09-08 13:45:52 +08:00
|
|
|
|
: m_id(n), m_weight(weight), m_italic(italic), m_OS2Table(NULL), IsPixel(false)
|
2018-04-13 14:05:08 +08:00
|
|
|
|
, FreeTypeMruCounter(mru), m_isSimSun(false), m_ggoFont(NULL), m_linkinited(false), m_linknum(0), m_os2Weight(0)
|
2016-05-30 17:12:15 +08:00
|
|
|
|
, m_SimSunID(0), count(1), m_fullname(fullname), m_familyname(familyname), m_hashinting(3), m_nFontFamily(0)
|
|
|
|
|
{
|
|
|
|
|
//m_set = set;
|
|
|
|
|
memset(m_ebmps, 0xff, sizeof(m_ebmps));
|
|
|
|
|
|
|
|
|
|
enum { FTC_MAX_SIZES_DEFAULT = 4 };
|
|
|
|
|
const CGdippSettings* pSettings = CGdippSettings::GetInstance();
|
|
|
|
|
m_nMaxSizes = pSettings->CacheMaxSizes();
|
|
|
|
|
if (!m_nMaxSizes)
|
|
|
|
|
m_nMaxSizes = FTC_MAX_SIZES_DEFAULT;
|
|
|
|
|
//extern BOOL g_EngineCreateFont;
|
|
|
|
|
if (pSettings->FontSubstitutes() < SETTING_FONTSUBSTITUTE_ALL)
|
|
|
|
|
m_ggoFont = CreateFont(10,0,0,0,weight,italic,0,0,DEFAULT_CHARSET,0,FONT_MAGIC_NUMBER,0,0,name);
|
|
|
|
|
//use magic number to create unsubstitud font
|
|
|
|
|
else
|
|
|
|
|
m_ggoFont = CreateFont(10,0,0,0,weight,italic,0,0,DEFAULT_CHARSET,0,0,0,0,name);
|
|
|
|
|
HDC hdc = CreateCompatibleDC(NULL);
|
|
|
|
|
HFONT old = SelectFont(hdc, m_ggoFont);
|
2020-12-06 18:38:08 +08:00
|
|
|
|
//获得字体的全称
|
2016-05-30 17:12:15 +08:00
|
|
|
|
|
|
|
|
|
int nSize=GetOutlineTextMetrics(hdc, 0, NULL);
|
|
|
|
|
if (nSize==0)
|
|
|
|
|
m_fullname = L"";
|
|
|
|
|
else
|
2020-12-06 17:00:05 +08:00
|
|
|
|
//if (m_fullname.size()==0) //构造函数中不提供,自己获取
|
2016-05-30 17:12:15 +08:00
|
|
|
|
{
|
|
|
|
|
LPOUTLINETEXTMETRIC otm = (LPOUTLINETEXTMETRIC)malloc(nSize);
|
|
|
|
|
memset(otm, 0, nSize);
|
|
|
|
|
otm->otmSize = nSize;
|
|
|
|
|
GetOutlineTextMetrics(hdc, nSize, otm);
|
2017-03-23 10:18:56 +08:00
|
|
|
|
m_fullname = (wstring)(LPWSTR)((DWORD_PTR)otm + (DWORD_PTR)otm->otmpFullName);
|
2016-05-30 17:12:15 +08:00
|
|
|
|
TCHAR * localname = (LPWSTR)((DWORD_PTR)otm+(DWORD_PTR)otm->otmpFamilyName);
|
2019-02-28 16:57:42 +08:00
|
|
|
|
wstring styleName = (wstring)(LPWSTR)((DWORD_PTR)otm + (DWORD_PTR)otm->otmpStyleName);
|
|
|
|
|
m_fullname = MakeUniqueFontName(m_fullname, localname, styleName);
|
|
|
|
|
|
2016-05-30 17:12:15 +08:00
|
|
|
|
TCHAR buff[LF_FACESIZE+1];
|
|
|
|
|
GetFontLocalName(localname, buff);
|
2020-12-06 17:00:05 +08:00
|
|
|
|
m_nFontFamily = otm->otmTextMetrics.tmPitchAndFamily & 0xF0; //获取字体家族,家族对应使用什么默认链接字体
|
2016-05-30 17:12:15 +08:00
|
|
|
|
m_familyname = (wstring)buff;
|
|
|
|
|
m_set = pSettings->FindIndividual(m_familyname.c_str());
|
|
|
|
|
m_ftWeight = CalcBoldWeight(/*weight*/700);
|
|
|
|
|
m_hash = StringHashFont(name);
|
2020-12-06 18:38:08 +08:00
|
|
|
|
if (m_familyname.size()>0 && m_familyname.c_str()[0]==L'@') //附加一个@
|
2016-05-30 17:12:15 +08:00
|
|
|
|
m_fullname = L'@'+m_fullname;
|
|
|
|
|
free(otm);
|
|
|
|
|
}
|
|
|
|
|
SelectFont(hdc, old);
|
|
|
|
|
DeleteDC(hdc);
|
|
|
|
|
|
2020-12-06 17:00:05 +08:00
|
|
|
|
//完成
|
2016-05-30 17:12:15 +08:00
|
|
|
|
// g_EngineCreateFont = false;
|
|
|
|
|
face_id_link[0]=(FTC_FaceID)NULL;
|
|
|
|
|
ggo_link[0] = NULL;
|
|
|
|
|
//g_fsetcache.Set((FTC_FaceID)n, set);
|
|
|
|
|
}
|
|
|
|
|
~FreeTypeFontInfo()
|
|
|
|
|
{
|
|
|
|
|
Erase();
|
|
|
|
|
DeleteFont(m_ggoFont);
|
|
|
|
|
if (m_OS2Table)
|
|
|
|
|
delete m_OS2Table;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HFONT GetGGOFont(){return m_ggoFont;};
|
|
|
|
|
int CalcNormalWeight() const
|
|
|
|
|
{
|
|
|
|
|
return m_set.GetNormalWeight();
|
|
|
|
|
}
|
|
|
|
|
int CalcBoldWeight(int weight) const
|
|
|
|
|
{
|
|
|
|
|
// return weight - FW_NORMAL) / 8;
|
|
|
|
|
// return ((weight - FW_NORMAL) / 12) + (m_set.GetBoldWeight() << 2);
|
|
|
|
|
weight = weight < FW_BOLD ? 0: /*(weight > FW_BOLD ?*/ 612;
|
|
|
|
|
if (weight <= FW_NORMAL) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return ((weight - FW_NORMAL) / 8) + (m_set.GetBoldWeight() << 2);
|
|
|
|
|
}
|
|
|
|
|
int CalcBoldWeight(const LOGFONT& lf) const
|
|
|
|
|
{
|
|
|
|
|
return CalcBoldWeight(lf.lfWeight);
|
|
|
|
|
}
|
|
|
|
|
void CalcItalicSlant(FT_Matrix& matrix) const
|
|
|
|
|
{
|
|
|
|
|
matrix.xx = 1 << 16;
|
|
|
|
|
// matrix.xy = 0x5800;
|
|
|
|
|
matrix.xy = (5 + m_set.GetItalicSlant()) << 12;
|
|
|
|
|
matrix.yx = 0;
|
|
|
|
|
matrix.yy = 1 << 16;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Equals(const StringHashFont& hash, int weight, bool italic) const
|
|
|
|
|
{
|
|
|
|
|
weight = CalcBoldWeight(weight);
|
|
|
|
|
return (m_ftWeight == weight && m_italic == italic && m_hash == hash);
|
|
|
|
|
}
|
|
|
|
|
void UpdateFontSetting()
|
|
|
|
|
{
|
|
|
|
|
m_ftWeight = CalcBoldWeight(700/*m_weight*/);
|
2020-12-06 17:00:05 +08:00
|
|
|
|
//清除字体链接
|
2016-05-30 17:12:15 +08:00
|
|
|
|
face_id_link[0]=NULL;
|
|
|
|
|
ggo_link[0]=NULL;
|
|
|
|
|
m_linknum = 0;
|
|
|
|
|
m_linkinited = false;
|
|
|
|
|
m_SimSunID = 0;
|
|
|
|
|
}
|
|
|
|
|
int GetFTLink(FTC_FaceID** llplink)
|
|
|
|
|
{
|
|
|
|
|
CCriticalSectionLock __lock(CCriticalSectionLock::CS_FONTLINK);
|
|
|
|
|
if (!*face_id_link)
|
|
|
|
|
Createlink();
|
|
|
|
|
*llplink = face_id_link;
|
|
|
|
|
return m_linknum;
|
|
|
|
|
}
|
|
|
|
|
int GetGGOLink(HFONT** llplink)
|
|
|
|
|
{
|
|
|
|
|
CCriticalSectionLock __lock(CCriticalSectionLock::CS_FONTLINK);
|
|
|
|
|
if (!*ggo_link)
|
|
|
|
|
Createlink();
|
|
|
|
|
*llplink = ggo_link;
|
|
|
|
|
return m_linknum;
|
|
|
|
|
}
|
|
|
|
|
FTC_FaceID GetSimSunID() {return m_SimSunID;}
|
|
|
|
|
|
|
|
|
|
INT_PTR GetId() const { return m_id; }
|
|
|
|
|
LPCTSTR GetName() const { return m_hash.c_str(); }
|
|
|
|
|
int GetFontWeight() const { return m_weight; }
|
|
|
|
|
int GetExactBoldWeight() const {return m_set.GetBoldWeight(); }
|
|
|
|
|
int GetFTWeight() const { return m_ftWeight; }
|
|
|
|
|
bool IsItalic() const { return m_italic; }
|
|
|
|
|
const StringHashFont& GetHash() const { return m_hash; }
|
|
|
|
|
|
|
|
|
|
const CFontSettings& GetFontSettings() const { return m_set; }
|
|
|
|
|
void SetFontSettings(const CFontSettings& set) { m_set = set;};
|
|
|
|
|
bool operator ==(const FreeTypeFontInfo& x) const { return (m_hash == x.m_hash); }
|
|
|
|
|
|
|
|
|
|
FreeTypeFontCache* GetCache(FTC_ScalerRec& scaler, const LOGFONT& lf);
|
|
|
|
|
bool EmbeddedBmpExist(int px);
|
|
|
|
|
void Erase()
|
|
|
|
|
{
|
|
|
|
|
CCriticalSectionLock __lock(CCriticalSectionLock::CS_FONTCACHE);
|
|
|
|
|
CacheArray::iterator it = m_cache.begin();
|
|
|
|
|
for (;it!=m_cache.end();++it)
|
|
|
|
|
{
|
|
|
|
|
delete it->second;
|
|
|
|
|
}
|
|
|
|
|
m_cache.clear();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class FreeTypeFontEngine : public FreeTypeGCCounter
|
|
|
|
|
{
|
|
|
|
|
private:
|
|
|
|
|
//typedef CArray<FreeTypeFontInfo*> FontListArray;
|
|
|
|
|
typedef map<myfont, FreeTypeFontInfo*> FontMap;
|
|
|
|
|
typedef map<wstring, FreeTypeFontInfo*> FullNameMap;
|
|
|
|
|
typedef vector<FreeTypeFontInfo*> FontList;
|
|
|
|
|
//FontListArray m_arrFontList;
|
|
|
|
|
int m_nMaxFaces;
|
|
|
|
|
int m_nMemUsed;
|
|
|
|
|
bool m_bAddOnFind;
|
|
|
|
|
FontMap m_mfontMap;
|
|
|
|
|
FullNameMap m_mfullMap;
|
|
|
|
|
FontList m_mfontList;
|
|
|
|
|
FT_Face* m_arrFace;
|
|
|
|
|
int m_nFaceCount;
|
|
|
|
|
void Compact();
|
|
|
|
|
int GrowFace()
|
|
|
|
|
{
|
|
|
|
|
FT_Face* a=(FT_Face*)malloc(m_nFaceCount*sizeof(FT_Face));
|
|
|
|
|
memcpy(a, m_arrFace, sizeof(FT_Face)*m_nFaceCount);
|
|
|
|
|
m_nFaceCount+=64;
|
|
|
|
|
m_arrFace = (FT_Face*)realloc(m_arrFace, sizeof(FT_Face) * m_nFaceCount);
|
|
|
|
|
memset(m_arrFace+m_nFaceCount-64, 0, sizeof(FT_Face)*64);
|
|
|
|
|
for (int i=0;i<m_nFaceCount-64;i++)
|
|
|
|
|
Assert(a[i]==m_arrFace[i]);
|
|
|
|
|
free(a);
|
|
|
|
|
return m_nFaceCount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
FreeTypeFontEngine()
|
|
|
|
|
: m_nMemUsed(0), m_nMaxFaces(0), m_bAddOnFind(false), m_nFaceCount(64)
|
|
|
|
|
{
|
|
|
|
|
enum { FTC_MAX_FACES_DEFAULT = 2 };
|
|
|
|
|
const CGdippSettings* pSettings = CGdippSettings::GetInstanceNoInit();
|
|
|
|
|
m_nMaxFaces = pSettings->CacheMaxFaces();
|
|
|
|
|
if (m_nMaxFaces == 0)
|
|
|
|
|
m_nMaxFaces = FTC_MAX_FACES_DEFAULT;
|
|
|
|
|
//m_arrFace = (FT_Face*)malloc(m_nFaceCount*sizeof(FT_Face));
|
|
|
|
|
//memset(m_arrFace, 0, sizeof(FT_Face)*m_nFaceCount);
|
|
|
|
|
}
|
|
|
|
|
~FreeTypeFontEngine()
|
|
|
|
|
{
|
|
|
|
|
TRACE(_T("MaxFaces: %d\n"), m_mfontMap.size());
|
|
|
|
|
TRACE(_T("MemUsed : %d\n"), m_nMemUsed);
|
|
|
|
|
//FontListArray& arr = m_arrFontList;
|
|
|
|
|
FullNameMap::const_iterator iter=m_mfullMap.begin();
|
|
|
|
|
for (;iter!=m_mfullMap.end();++iter)
|
|
|
|
|
iter->second->Release();
|
|
|
|
|
//free(m_arrFace);
|
|
|
|
|
}
|
|
|
|
|
int CalcBoldWeight(int weight) const
|
|
|
|
|
{
|
|
|
|
|
return weight < FW_BOLD ? 0: FW_BOLD;
|
|
|
|
|
}
|
|
|
|
|
FreeTypeFontInfo* AddFont(LPCTSTR lpFaceName, int weight, bool italic, BOOL* bIsFontLoaded = NULL);
|
|
|
|
|
FreeTypeFontInfo* AddFont(void* lpparams);
|
|
|
|
|
int GetFontIdByName(LPCTSTR lpFaceName, int weight, bool italic);
|
|
|
|
|
// LPCTSTR GetFontById(int faceid, int& weight, bool& italic);
|
|
|
|
|
FreeTypeFontInfo* FindFont(LPCTSTR lpFaceName, int weight, bool italic, bool AddOnFind = true, BOOL* bIsFontLoaded=NULL);
|
|
|
|
|
FreeTypeFontInfo* FindFont(int faceid);
|
|
|
|
|
FreeTypeFontInfo* FindFont(void* lpparams);
|
|
|
|
|
|
|
|
|
|
bool FontExists(LPCTSTR lpFaceName, int weight, bool italic)
|
|
|
|
|
{
|
|
|
|
|
return !!FindFont(lpFaceName, weight, italic);
|
|
|
|
|
}
|
|
|
|
|
BOOL RemoveFont(LPCWSTR FontName);
|
|
|
|
|
BOOL RemoveFont(FreeTypeFontInfo* fontinfo);
|
|
|
|
|
BOOL RemoveThisFont(FreeTypeFontInfo* fontinfo, LOGFONT* lg);
|
2020-12-06 18:38:08 +08:00
|
|
|
|
//メモリ使用量カウンタ
|
2016-05-30 17:12:15 +08:00
|
|
|
|
void AddMemUsed(int x)
|
|
|
|
|
{
|
|
|
|
|
m_nMemUsed += x;
|
|
|
|
|
}
|
|
|
|
|
void SubMemUsed(int x)
|
|
|
|
|
{
|
|
|
|
|
m_nMemUsed -= x;
|
|
|
|
|
if (m_nMemUsed < 0)
|
|
|
|
|
m_nMemUsed = 0;
|
|
|
|
|
}
|
|
|
|
|
template <class T>
|
|
|
|
|
void AddMemUsedObj(T* /*p*/)
|
|
|
|
|
{
|
|
|
|
|
AddMemUsed(sizeof(T));
|
|
|
|
|
}
|
|
|
|
|
template <class T>
|
|
|
|
|
void SubMemUsedObj(T* /*p*/)
|
|
|
|
|
{
|
|
|
|
|
SubMemUsed(sizeof(T));
|
|
|
|
|
}
|
|
|
|
|
void ReloadAll()
|
|
|
|
|
{
|
2020-12-06 17:00:05 +08:00
|
|
|
|
//重新载入全部字体,即清空所有字体缓存
|
2016-05-30 17:12:15 +08:00
|
|
|
|
COwnedCriticalSectionLock __olock(2);
|
|
|
|
|
CCriticalSectionLock __lock;
|
|
|
|
|
CGdippSettings* pSettings = CGdippSettings::GetInstance();
|
|
|
|
|
|
|
|
|
|
FullNameMap::const_iterator iter=m_mfullMap.begin();
|
|
|
|
|
for (;iter!=m_mfullMap.end();)
|
|
|
|
|
{
|
|
|
|
|
FreeTypeFontInfo* p =iter->second;
|
|
|
|
|
if (p)
|
|
|
|
|
{
|
|
|
|
|
/*
|
2020-12-06 17:00:05 +08:00
|
|
|
|
if (p->GetFullName()!=iter->first) //是替换字体
|
2016-05-30 17:12:15 +08:00
|
|
|
|
{
|
2020-12-06 17:00:05 +08:00
|
|
|
|
p->Release(); //释放掉多重引用
|
2016-05-30 17:12:15 +08:00
|
|
|
|
m_mfullMap.erase(iter++);
|
|
|
|
|
continue;
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
p->Erase();
|
|
|
|
|
p->SetFontSettings(pSettings->FindIndividual(p->GetName()));
|
|
|
|
|
p->UpdateFontSetting();
|
|
|
|
|
}
|
|
|
|
|
++iter;
|
|
|
|
|
}
|
|
|
|
|
//m_mfontMap.clear();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2020-12-06 18:38:08 +08:00
|
|
|
|
//GetFontDataのメモリストリーム
|
2016-05-30 17:12:15 +08:00
|
|
|
|
class FreeTypeSysFontData
|
|
|
|
|
{
|
|
|
|
|
private:
|
|
|
|
|
HDC m_hdc;
|
|
|
|
|
HFONT m_hOldFont;
|
|
|
|
|
bool m_isTTC;
|
|
|
|
|
bool m_locked;
|
|
|
|
|
void* m_pMapping;
|
|
|
|
|
DWORD m_dwSize;
|
|
|
|
|
FT_Face m_ftFace;
|
|
|
|
|
wstring m_name;
|
|
|
|
|
FT_StreamRec m_ftStream;
|
|
|
|
|
|
|
|
|
|
FreeTypeSysFontData()
|
|
|
|
|
: m_hdc(NULL)
|
|
|
|
|
, m_hOldFont(NULL)
|
|
|
|
|
, m_isTTC(false)
|
|
|
|
|
, m_locked(false)
|
|
|
|
|
, m_pMapping(NULL)
|
|
|
|
|
, m_dwSize(0)
|
|
|
|
|
, m_ftFace(NULL)
|
|
|
|
|
{
|
|
|
|
|
ZeroMemory(&m_ftStream, sizeof(FT_StreamRec));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static unsigned long IoFunc(FT_Stream stream, unsigned long offset, unsigned char* buffer, unsigned long count);
|
|
|
|
|
static void CloseFunc(FT_Stream stream);
|
|
|
|
|
bool OpenFaceByIndex(int index);
|
|
|
|
|
bool Init(LPCTSTR name, int weight, bool italic);
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
static FreeTypeSysFontData* CreateInstance(LPCTSTR name, int weight, bool italic);
|
|
|
|
|
~FreeTypeSysFontData()
|
|
|
|
|
{
|
|
|
|
|
if (m_pMapping) {
|
|
|
|
|
UnmapViewOfFile(m_pMapping);
|
|
|
|
|
}
|
|
|
|
|
if (m_hOldFont) {
|
|
|
|
|
DeleteFont(SelectFont(m_hdc, m_hOldFont));
|
|
|
|
|
}
|
|
|
|
|
if (m_hdc) {
|
|
|
|
|
DeleteDC(m_hdc);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FT_Face GetFace()
|
|
|
|
|
{
|
|
|
|
|
FT_Face face = m_ftFace;
|
|
|
|
|
m_ftFace = NULL;
|
|
|
|
|
return face;
|
|
|
|
|
}
|
|
|
|
|
};
|