#ifndef _gdiFONT_
#define _gdiFONT_
/*<<<***************************************************************************
The MIT License (MIT)

Copyright(C) 2013 - 2015 Marc Mirti Mancinelli, Christophe Lardau and Philippe Pamart (xdcube.org)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
////////////////////////////////////////////////////////////////////////////////
#Title: gdiFont
#Project: xdcGdi
////////////////////////////////////////////////////////////////////////////////
#Author: Marc MIRTI MANCINELLI
#History:
<15/09/2013: creation.
12/02/2014: this notice inserted.
***************************************************************************>>>*/

#ifndef _gdiBASE_
#	include "gdiBase.h"
#endif

#ifndef _gdiDC_
#	include "gdiDC.h"
#endif

interface sIxbXmlSource;
class gdiFont;
interface gdiEXPORT cbIgdiFontChanged
{
	virtual void onFontChanged(gdiFont *pFont) = 0;
};

enum gdiWeight
{
	gdiWeightDefault = -1,
	gdiWeightDontCare = FW_DONTCARE,		// 0
	gdiWeightThin = FW_THIN,				// 100
	gdiWeightExtraLight = FW_EXTRALIGHT,	// 200 
	gdiWeightLight = FW_LIGHT,				// 300 
	gdiWeightNormal = FW_NORMAL,			// 400 
	gdiWeightMedium = FW_MEDIUM,			// 500 
	gdiWeightSemiBold = FW_SEMIBOLD,		// 600 
	gdiWeightBold = FW_BOLD,				// 700 
	gdiWeightExtraBold = FW_EXTRABOLD,		// 800 
	gdiWeightHeavy = FW_HEAVY,				// 900 
};

enum gdiPitch
{
	gdiPitchDefault = -1,
	gdiPitchDontCare = DEFAULT_PITCH,
		gdiPitchFixed = FIXED_PITCH,
		gdiPitchVariable = VARIABLE_PITCH
};

enum gdiCharSet
{
	gdiCharSetDefault = -1,
	gdiCharSetAnsi = ANSI_CHARSET,
		gdiCharSetMac = MAC_CHARSET,
		gdiCharSetOEM = OEM_CHARSET
};

enum gdiPrecis
{
	gdiPrecisDefault = -1,
	gdiPrecisDontCare = OUT_DEFAULT_PRECIS,	
									// Specifies the default font mapper behavior. 
	gdiPrecisDevice = OUT_DEVICE_PRECIS,	
									// Instructs the font mapper to choose a Device 
									// font when the system contains multiple fonts 
									// with the same name. 
	gdiPrecisOutline = OUT_OUTLINE_PRECIS,	
									// Windows NT: This value instructs the font mapper
									// to choose from TrueType and other outline-based 
									// fonts. 
	gdiPrecisRaster = OUT_RASTER_PRECIS,	
									// Instructs the font mapper to choose a raster font 
									// when the system contains multiple fonts with the 
									// same name. 
	gdiPrecisString = OUT_STRING_PRECIS,	
									// This value is not used by the font mapper, but it 
									// is returned when raster fonts are enumerated. 
	gdiPrecisStroke = OUT_STROKE_PRECIS,	
									// Windows NT: This value is not used by the 
									// font mapper, but it is returned when TrueType, 
									// other outline-based fonts, and vector fonts are 
									// enumerated. 
									// Windows 95: This value is used to map vector fonts, 
									// and is returned when TrueType or vector fonts 
									// are enumerated. 
	gdiPrecisTTonly = OUT_TT_ONLY_PRECIS,	
									// Instructs the font mapper to choose from only 
									// TrueType fonts. If there are no TrueType fonts 
									// installed in the system, the font mapper returns 
									// to default behavior. 
	gdiPrecisTT = OUT_TT_PRECIS,			
									// Instructs the font mapper to choose a TrueType 
									// font when the system contains multiple fonts 
									// with the same name. 
};


enum gdiQuality
{
	gdiQualityDefault = -1,
//Specifies the output quality. The output quality defines how carefully GDI must attempt
	// to match the logical-font attributes to those of an actual physical font. 
	// It can be one of the following values: Value Meaning 
	gdiQualityDontCare = DEFAULT_QUALITY, 
							// Appearance of the font does not matter. 
	gdiQualityDraft = DRAFT_QUALITY,	
							//Appearance of the font is less important than 
							// when the PROOF_QUALITY value is used. For GDI raster fonts, 
							// scaling is enabled, which means that more font sizes are available, 
							// but the quality may be lower. Bold, italic, underline, and 
							// strikeout fonts are synthesized if necessary. 
	gdiQualityProof = PROOF_QUALITY, 
							// Character quality of the font is more important than 
							// exact matching of the logical-font attributes. 
							// For GDI raster fonts, scaling is disabled and the font closest 
							// in size is chosen. Although the chosen font size may not be 
							// mapped exactly when PROOF_QUALITY is used, the quality of the font 
							// is high and there is no distortion of appearance. 
							// Bold, italic, underline, and strikeout fonts are synthesized 
							// if necessary.
};

class gdiEXPORT gdiFontSt
{
public:
	gdiFontSt()
	{
		m_sz = 0;
		m_weight = gdiWeightDefault;
		m_quality = gdiQualityDefault;
		m_precis = gdiPrecisDefault;
		m_charSet = gdiCharSetDefault;
		m_pitch = gdiPitchDefault;
		m_orient = 0;
	}
	inline void Empty() 
	{
		m_name.Empty();
		m_sz = 0;
		m_bold.Empty();
		m_italic.Empty();
		m_under.Empty();
		m_weight = gdiWeightDefault;
		m_quality = gdiQualityDefault;
		m_precis = gdiPrecisDefault;
		m_charSet = gdiCharSetDefault;
		m_pitch = gdiPitchDefault;
		m_orient = 0;
	}
	int Compare(gdiFontSt &st) const
	{
		int ret = m_name.CompareNoCase(st.m_name);
		if (ret != 0)
			return ret;
		if (m_sz != st.m_sz)
			return m_sz - st.m_sz;
		if ((ret = boolCompare(m_bold,st.m_bold))!=0)
			return ret;
		if ((ret = boolCompare(m_italic,st.m_italic))!=0)
			return ret;
		if ((ret = boolCompare(m_under,st.m_under))!=0)
			return ret;
		if (m_weight != st.m_weight)
			return int(m_weight) - int(st.m_weight);
		if (m_quality != st.m_quality)
			return int(m_quality) - int(st.m_quality);
		if (m_precis != st.m_precis)
			return int(m_precis) - int(st.m_precis);
		if (m_charSet != st.m_charSet)
			return int(m_charSet) - int(st.m_charSet);
		if (m_pitch != st.m_pitch)
			return int(m_pitch) - int(st.m_pitch);
		if (m_orient != st.m_orient)
			return m_orient - st.m_orient;
		return 0;
	}
	int boolCompare(bool bVal1,bool bVal2) const
	{
		if (bVal1 == bVal2)
			return 0;
		if (bVal1)
			return 1;
		return -1;
	}

	xbStringW			m_name;
	int					m_sz;
	xbBool				m_bold;
	xbBool				m_italic;
	xbBool				m_under;

	gdiWeight			m_weight;
	gdiQuality			m_quality;
	gdiPrecis			m_precis;
	gdiCharSet			m_charSet;
	gdiPitch			m_pitch;

	int					m_orient; // in tenths of degrees between x-axis and characters base line.
};
#define gdiFONTST_ALL		0x000007FF
#define gdiFONTST_NAME		0x00000001
#define gdiFONTST_SZ		0x00000002
#define gdiFONTST_BOLD		0x00000004
#define gdiFONTST_ITALIC	0x00000008
#define gdiFONTST_UNDER		0x00000010
#define gdiFONTST_WEIGHT	0x00000020
#define gdiFONTST_QUALITY	0x00000040
#define gdiFONTST_PRECIS	0x00000080
#define gdiFONTST_CHARSET	0x00000100
#define gdiFONTST_PITCH		0x00000200
#define gdiFONTST_ORIENT	0x00000400

class gdiFontEngineBase;
class gdiFontObject:protected gdiFontSt
{
public:
	gdiFontObject()
	{
		m_cRef = 1;
		m_pEngine = NULL;
		m_hFont = NULL;
	}
	gdiFontObject(const gdiFontSt &font)
	{
		m_cRef = 1;
		m_pEngine = NULL;

		m_name = font.m_name;
		m_sz = font.m_sz;
		m_orient = font.m_orient;
		m_bold = font.m_bold;
		m_italic = font.m_italic;
		m_under = font.m_under;
		m_weight = font.m_weight;
		m_quality = font.m_quality;
		m_precis = font.m_precis;
		m_charSet = font.m_charSet;
		m_pitch = font.m_pitch;
		m_sizeRef.cx = -1;

		m_hFont = NULL;
	}
	~gdiFontObject()
	{
		eProtectTrace(fontDestroy(););
		xbRdbgAssert(!m_pEngine && !m_hFont);
	}

	operator HFONT() const;
	HFONT GetHandle() const;

	void fontAddRef()
	{
		xbInterlockIncrement32(&m_cRef);
	}
	void fontRelease()
	{
		xbRdbgAssert(m_cRef>0);
		if (::xbInterlockDecrement32(&m_cRef)==0
			&& engineRelease())
			delete this;
	}
	xbHeapNewImpl(gdiFontObject);
	void engineSet(gdiFontEngineBase *pEng);
	int Compare(gdiFontSt &st) const {return gdiFontSt::Compare(st);}
	void fontCreate() const;
	gdiSizeLow getFontSizeRef() const;
	ulong getFontHeightRef() const;
	ulong getFontWidthRef() const;
	ulong getFontSpaceWidth() const;

	const TEXTMETRICW &getFontMetrics() const;
	xbStringW getTextFace() const;
protected:
	void fontDestroy() const;
	bool engineRelease();

	long			m_cRef;
	mutable ulong	m_spaceWidth;
	mutable HFONT	m_hFont;
	gdiFontEngineBase	*m_pEngine;
	mutable gdiSizeLow	m_sizeRef;
	TEXTMETRICW		m_metrics;
};

class gdiEXPORT gdiFont:protected gdiFontSt
{
public:
	gdiFont(cbIgdiFontChanged *pCB,bool bEmpty = false);
	gdiFont(cbIgdiFontChanged *pCB,const gdiFont &font);
	gdiFont(gdiFont *pFontParent);
	gdiFont(gdiFontEngineBase &engine,cbIgdiFontChanged *pCB,bool bEmpty = false);
	gdiFont(gdiFontEngineBase &engine,cbIgdiFontChanged *pCB,const gdiFont &font);
	gdiFont(gdiFontEngineBase &engine,gdiFont *pFontParent);
	~gdiFont()
	{
		eProtectTrace(fontRelease(););
	}
	void SetCB(cbIgdiFontChanged *pCB)
	{
		m_pCB = pCB;
	}
	void SetFontParent(gdiFont *pFontParent)
	{
		m_pParent = pFontParent;
		m_cParentChg = 0;
	}
	void SetFontEngine(gdiFontEngineBase *pEngine)
	{
		m_pEngine = pEngine;
	}
	gdiFont &operator=(const gdiFont &font);

	operator HFONT() const;
	HFONT GetHandle() const;

	bool	Set(const gdiFont &font,bool update = true);
	bool	SetAll(const xbStringW &str,int sz,bool bold,bool italic,bool under,bool update = true);
	bool	SetName(const xbStringW &str,bool update = true);
	bool	SetSize(int sz,bool update = true);
	bool	SetUnderline(bool flg,bool update = true);
	bool	SetItalic(bool flg,bool update = true);
	bool	SetBold(bool flg,bool update = true);
	bool	SetUnderline(const xbBool &flg,bool update = true);
	bool	SetItalic(const xbBool &flg,bool update = true);
	bool	SetBold(const xbBool &flg,bool update = true);

	bool	SetWeight(gdiWeight val,bool update = true);
	bool	SetQuality(gdiQuality val,bool update = true);
	bool	SetPrecis(gdiPrecis val,bool update = true);
	bool	SetCharSet(gdiCharSet val,bool update = true);
	bool	SetPitch(gdiPitch val,bool update = true);

	bool	SetOrientation(int orient,bool update = true); //not transmitted by copy op, reason : draw fonts with orientation != 0 change the code to draw them !

	bool	SetEmpty(bool bEmpty,bool update = true);
	inline void Empty(bool update = true,bool bEmptyFlagSet = true) 
	{
		SetEmpty(bEmptyFlagSet,false);
		m_shadDec = 0;
		gdiFontSt::Empty();
		fontUpdate(update);
	}
	bool	SetShadowDec(int shadDec,bool update = true);
	
	xbStringW	GetName() const {return m_name;}
	int			GetSize() const {return m_sz;}
	bool		GetBold() const {return m_bold;}
	bool		GetItalic() const {return m_italic;}
	bool		GetUnderline() const {return m_under;}

	gdiWeight	GetWeight() const {return m_weight;}
	gdiQuality	GetQuality() const {return m_quality;}
	gdiPrecis	GetPrecis() const {return m_precis;}
	gdiCharSet	GetCharSet() const {return m_charSet;}
	gdiPitch	GetPitch() const {return m_pitch;}

	int			GetOrientation() const {return m_orient;}

	bool		IsEmpty() const {return m_bEmpty;}
	bool		IsValid() const {return !m_bEmpty;}

	bool		operator==(const gdiFont &font) const
	{
		if (m_bEmpty || font.m_bEmpty)
			return m_bEmpty == font.m_bEmpty;

		return m_name == font.m_name 
			&& m_sz == font.m_sz
			&& m_bold == font.m_bold
			&& m_italic == font.m_italic
			&& m_under == font.m_under
//			&& m_orient == font.m_orient
			&& m_shadDec == font.m_shadDec
			&& m_weight == font.m_weight
			&& m_quality == font.m_quality
			&& m_precis == font.m_precis
			&& m_charSet == font.m_charSet
			&& m_pitch == font.m_pitch;
	}
	bool		operator!=(const gdiFont &font) const
	{
		if (m_bEmpty || font.m_bEmpty)
			return m_bEmpty != font.m_bEmpty;

		return m_name != font.m_name 
			|| m_sz != font.m_sz
			|| m_bold != font.m_bold
			|| m_italic != font.m_italic
			|| m_under != font.m_under
//			|| m_orient != font.m_orient
			|| m_shadDec != font.m_shadDec
			|| m_weight != font.m_weight
			|| m_quality != font.m_quality
			|| m_precis != font.m_precis
			|| m_charSet != font.m_charSet
			|| m_pitch != font.m_pitch;
	}
	
	bool xmlSetParam(const xbString &prefix,const xbString &propname,const xbString &propvalue,bool bDefault,bool *pbUpdated=NULL);

	bool HasDefaults() const
	{
		if (m_bEmpty || m_name.IsEmpty() 
			|| m_sz == 0 
			|| m_bold.IsDefault()
			|| m_italic.IsDefault()
			|| m_under.IsDefault()
			|| m_shadDec <= 0
			|| m_weight == gdiWeightDefault
			|| m_quality == gdiQualityDefault
			|| m_precis == gdiPrecisDefault
			|| m_charSet == gdiCharSetDefault
			|| m_pitch == gdiPitchDefault
			) return true;
		return false;
	}
	bool HasValids() const
	{
		if (!m_bEmpty && (m_name.IsValid() 
			|| m_sz != 0 
			|| m_bold.IsValid()
			|| m_italic.IsValid()
			|| m_under.IsValid()
			|| m_shadDec > 0
			|| m_weight != gdiWeightDefault
			|| m_quality != gdiQualityDefault
			|| m_precis != gdiPrecisDefault
			|| m_charSet != gdiCharSetDefault
			|| m_pitch != gdiPitchDefault
			)) return true;
		return false;
	}
	bool SetDefaults(const gdiFont &font,bool bUpdate = true)
	{
		if (m_bEmpty)
			return Set(font,bUpdate);

		bool toupdate = false;
		if (m_name.IsEmpty() && font.m_name.IsValid()
			&& SetName(font.m_name,false)) toupdate = true;
		if (m_sz == 0 && font.m_sz != 0
			&& SetSize(font.m_sz,false)) toupdate = true;
		if (m_bold.IsDefault() && font.m_bold.IsValid()
			&& SetBold(font.m_bold,false)) toupdate = true;
		if (m_italic.IsDefault() && font.m_italic.IsValid()
			&& SetItalic(font.m_italic,false)) toupdate = true;
		if (m_under.IsDefault() && font.m_under.IsValid()
			&& SetUnderline(font.m_under,false)) toupdate = true;
		if (m_shadDec <= 0 && font.m_shadDec > 0 
			&& SetShadowDec(font.m_shadDec,false)) toupdate = true;

		if (m_weight == gdiWeightDefault && font.m_weight != gdiWeightDefault
			&& SetWeight(font.m_weight,false)) toupdate = true;
		if (m_quality == gdiQualityDefault && font.m_quality != gdiQualityDefault
			&& SetQuality(font.m_quality,false)) toupdate = true;
		if (m_precis == gdiPrecisDefault && font.m_precis != gdiPrecisDefault
			&& SetPrecis(font.m_precis,false)) toupdate = true;
		if (m_charSet == gdiCharSetDefault && m_charSet != gdiCharSetDefault
			&& SetCharSet(font.m_charSet,false)) toupdate = true;
		if (m_pitch == gdiPitchDefault && font.m_pitch != gdiPitchDefault
			&& SetPitch(font.m_pitch,false)) toupdate = true;

		if (toupdate && bUpdate) fontUpdate(true);
		return toupdate;
	}
	bool SetValids(const gdiFont &font,bool bUpdate = true)
	{
		if (font.m_bEmpty) return false;

		bool toupdate = false;
		if (!font.m_name.IsEmpty() && SetName(font.m_name,false)) toupdate = true;
		if (font.m_sz != 0 && SetSize(font.m_sz,false)) toupdate = true;
		if (font.m_bold.IsValid() && SetBold(font.m_bold,false)) toupdate = true;
		if (font.m_italic.IsValid() && SetItalic(font.m_italic,false)) toupdate = true;
		if (font.m_under.IsValid() && SetUnderline(font.m_under,false)) toupdate = true;
		if (font.m_shadDec > 0 && SetShadowDec(font.m_shadDec,false)) toupdate = true;

		if (font.m_weight != gdiWeightDefault
			&& SetWeight(font.m_weight,false)) toupdate = true;
		if (font.m_quality != gdiQualityDefault
			&& SetQuality(font.m_quality,false)) toupdate = true;
		if (font.m_precis != gdiPrecisDefault
			&& SetPrecis(font.m_precis,false)) toupdate = true;
		if (font.m_charSet != gdiCharSetDefault
			&& SetCharSet(font.m_charSet,false)) toupdate = true;
		if (font.m_pitch != gdiPitchDefault
			&& SetPitch(font.m_pitch,false)) toupdate = true;

		if (toupdate && bUpdate) fontUpdate(true);

		return toupdate;
	}

	gdiSizeLow	GetFontSizeRef() const;
	ulong	GetFontHeightRef() const;
	ulong	GetFontWidthRef() const;
	ulong	GetFontSpaceWidth() const;

	const TEXTMETRICW &GetFontMetrics() const;

	ulong GetFontHeightPx() const
	{
		return GetFontMetrics().tmHeight;
	}
	ulong GetFontHeightAscent() const
	{
		return GetFontMetrics().tmAscent;
	}
	ulong GetFontHeightDescent() const
	{
		return GetFontMetrics().tmDescent;
	}
	ulong GetFontWidthPx() const
	{
		return GetFontMetrics().tmAveCharWidth;
	}
	ulong GetFontWidthMaxPx() const
	{
		return GetFontMetrics().tmMaxCharWidth;
	}
	ulong GetFontOverHang() const
	{
		return GetFontMetrics().tmOverhang;
	}
	xbStringW GetTextFace() const;

	gdiSizeLow	GetTextSize(IgdiDC &dc,const xbStringW &s,bool bShadowDec = false) const;
	gdiSizeLow	GetTextSize(IgdiDC &dc,LPCWSTR pstr,int len,bool bShadowDec = false) const;
	inline gdiSizeLow	GetTextSize(IgdiDC &dc,int width,const xbStringW &s,bool bShadowDec = false) const
	{
		return GetTextSize(dc,width,s,s.GetLength(),bShadowDec);
	}
	gdiSizeLow	GetTextSize(IgdiDC &dc,int width,LPCWSTR pstr,int len,bool bShadowDec = false) const;

	gdiSizeLow	GetTextSizeNorm(IgdiDC &dc,const xbStringW &s,bool bShadowDec = false) const
	{
		return gdiSizeLow(GetTextSize(dc,s,bShadowDec).cx,GetFontHeightPx());
	}
	gdiSizeLow	GetTextSizeNorm(IgdiDC &dc,LPCWSTR pstr,int len,bool bShadowDec = false) const
	{
		return gdiSizeLow(GetTextSize(dc,pstr,len,bShadowDec).cx,GetFontHeightPx());
	}

	inline void DrawText(IgdiDC &dc,const gdiRectLow &rect,const xbStringW &s,const gdiColor *pclr,const gdiColor *pshadclr = NULL,bool bMultiLine = false) const
	{
		DrawText(dc,rect,s,s.GetLength(),pclr,pshadclr,bMultiLine);
	}
	void DrawText(IgdiDC &dc,const gdiRectLow &rect,LPCWSTR pstr,int len,const gdiColor *pclr,
		const gdiColor *pshadclr = NULL,bool bMultiLine = false) const;
	void DrawText(IgdiDC &dc,const gdiRectLow &rect,LPCWSTR pstr,int len,const gdiColor *pclr,
		const gdiColor *pshadclr,gdiSizeLow *pCalcSz,
		const gdiPointLow *pPtStart,gdiPointLow *pPtEnd,int *pHeightLn,const gdiPen *punderlinePen = NULL) const;

	inline int GetShadowDec() const
	{
/*		if (m_bold) 
		{
			if (m_BoldShadDec<=0) return 1;
			return m_BoldShadDec;
		}*/
		if (m_shadDec<=0) return 1;
		return m_shadDec;
	}
	inline void IncShadowSize(gdiSizeLow &sz) const
	{
		int dec = GetShadowDec();
		sz.cx += dec;
		sz.cy += dec;
	}

	void OwnData()
	{
		m_name.OwnData();
	}
	ulong GetFontChg() const {return m_cChg;}
	void fontParentCheck();
	uint64 GetFontMark() const 
	{
		((gdiFont*)this)->fontCheck();
		return m_cChg+(uint64(xbNptr(m_pFont))<<32);
	}
	ulong GetFontShortMark() const 
	{
		((gdiFont*)this)->fontParentCheck();
		return m_cChg;
	}
protected:
	gdiFont(const gdiFont &font);

	void			fontCreate();
	void			fontUpdate(bool update);
	void			fontRelease()
	{
		gdiFontObject *pFont = m_pFont;
		if (!pFont)
			return;
		m_pFont = NULL;
		pFont->fontRelease();
	}
	void			fontStFeed(gdiFontSt *pFontSt,ulong flags);
	gdiFontObject	*fontAddRef();
	inline void fontCheck()
	{
		fontParentCheck();
		if (!m_pFont)
			fontCreate();
	}

	gdiFontEngineBase	*m_pEngine;
	cbIgdiFontChanged	*m_pCB;
	gdiFont				*m_pParent;
	ulong				m_cChg,m_cParentChg;
	bool				m_bEmpty;

	gdiFontObject		*m_pFont;
	int					m_shadDec;
private:
	xbDclNoNewForObject(gdiFont);
};

class gdiEXPORT __declspec(uuid("{5282146B-E03C-4535-9858-076699D91E69}"))
	gdiFontEngineBase:public xbEngine
{
public:
	gdiFontEngineBase(const char *pLabel,const xbEngines &engUsed = xbEngines())
		:xbEngine(xbEngineStart_Auto,pLabel,engUsed)
	{
	}
	virtual ~gdiFontEngineBase()
	{
		Destroy();
	}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(gdiFontEngineBase);
		return xbEngine::GetInterface(riid,ppInterf);
	}

	gdiFontObject *fontDefaultAddRef();
	gdiFontObject *fontAddRef(const gdiFontSt &fontSt);
	/*
	{
		xbLock lckStart(this);
	}
	*/
	virtual bool isLockedByMe() const {return m_sect.IsLockedByMe();}

	mutable xbSectShare	m_sect;

	virtual IgdiDC &GetDC() const = 0; 
protected:
	virtual void onStart() {}
	virtual bool onStop(bool) 
	{
		xbSectLock	lck(&m_sect);
		gdiFontObject **ppFont = m_arrFont.Begin();
		gdiFontObject **ppFontEnd = m_arrFont.End();
		while(ppFont < ppFontEnd)
		{
			(*ppFont)->engineSet(NULL);
			ppFont++;
		}
		m_arrFont.Empty();
		return true;
	}

	xbArray<gdiFontObject*>	m_arrFont;
	static int fontFindCb(gdiFontObject* const &pFont,const void *pFontSt)
	{
		return pFont->Compare(*(gdiFontSt*)pFontSt);
	}
	void onFontReleased(gdiFontObject *pFont);
	friend gdiFontObject;
};

class gdiEXPORT __declspec(uuid("{B346DBDB-0B3E-4a5e-893D-F8B4CD0054F4}"))
	gdiFontEngineScreen:public gdiFontEngineBase
{
public:
	gdiFontEngineScreen(const char *pLabel,const xbEngines &engUsed = xbEngines())
		:gdiFontEngineBase(pLabel,engUsed)
	{
		m_thId = 0;
	}
	virtual ~gdiFontEngineScreen()
	{
		Destroy();
	}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(gdiFontEngineScreen);
		return gdiFontEngineBase::GetInterface(riid,ppInterf);
	}
	virtual IgdiDC &GetDC() const 
	{
		if (m_thId == 0)
			m_thId = ::GetCurrentThreadId();
		xbRdbgAssert(m_thId == ::GetCurrentThreadId());
		return (IgdiDC&)m_dc;
	}
protected:
	gdiScreenDC		m_dc;
	mutable ulong	m_thId;
};

class gdiEXPORT __declspec(uuid("{DADEE65A-6B6C-4764-BB97-C4B8D98205A4}"))
	gdiFontEngineDC:public gdiFontEngineBase
{
public:
	gdiFontEngineDC(IgdiDC *pDc,const char *pLabel,const xbEngines &engUsed = xbEngines())
		:gdiFontEngineBase(pLabel,engUsed)
	{
		m_prDc = pDc;
	}
	virtual ~gdiFontEngineDC()
	{
		Destroy();
	}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(gdiFontEngineDC);
		return gdiFontEngineBase::GetInterface(riid,ppInterf);
	}

	virtual IgdiDC &GetDC() const 
	{
		if (m_thId == 0)
			m_thId = ::GetCurrentThreadId();
		xbRdbgAssert(m_thId == ::GetCurrentThreadId());
		return *m_prDc;
	}
protected:
	xbRefPtr<IgdiDC>	m_prDc;
	mutable ulong		m_thId;
};

extern gdiFontEngineScreen	gdiEXPORT g_gdiFontEngine;


#endif
