// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1998 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.

#include "stdafx.h"

#ifdef AFXCTL_CORE2_SEG
#pragma code_seg(AFXCTL_CORE2_SEG)
#endif

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define new DEBUG_NEW

/////////////////////////////////////////////////////////////////////////////
// CFontHolder

CFontHolder::CFontHolder(LPPROPERTYNOTIFYSINK pNotify) :
	m_pFont(NULL),
	m_dwConnectCookie(0),
	m_pNotify(pNotify)
{
	ASSERT_NULL_OR_POINTER(pNotify, IPropertyNotifySink);
}

void CFontHolder::SetFontNotifySink(LPPROPERTYNOTIFYSINK pNotify)
{
	ASSERT_NULL_OR_POINTER(pNotify, IPropertyNotifySink);
	m_pNotify = pNotify;
}

CFontHolder::~CFontHolder()
{
	ReleaseFont();
}

void CFontHolder::ReleaseFont()
{
	if ((m_pFont != NULL) && (m_pNotify != NULL))
	{
		AfxConnectionUnadvise(m_pFont, IID_IPropertyNotifySink, m_pNotify,
			FALSE, m_dwConnectCookie);
	}

	RELEASE(m_pFont);
}

AFX_STATIC_DATA const FONTDESC _afxFontDescDefault =
	{ sizeof(FONTDESC), OLESTR("MS Sans Serif"), FONTSIZE(12), FW_NORMAL,
	  DEFAULT_CHARSET, FALSE, FALSE, FALSE };

void CFontHolder::InitializeFont(const FONTDESC* pFontDesc,
	LPDISPATCH pFontDispAmbient)
{
	ASSERT_NULL_OR_POINTER(pFontDesc, FONTDESC);
	ASSERT_NULL_OR_POINTER(pFontDispAmbient, IDispatch);
#ifdef _DEBUG
	if (pFontDesc != NULL)
		ASSERT(pFontDesc->cbSizeofstruct == sizeof(FONTDESC));
#endif

	// Release any previous font, in preparation for creating a new one.
	ReleaseFont();

	LPFONT pFontAmbient;
	LPFONT pFontNew = NULL;

	if ((pFontDispAmbient != NULL) &&
		SUCCEEDED(pFontDispAmbient->QueryInterface(IID_IFont,
				(LPVOID*)&pFontAmbient)))
	{
		ASSERT_POINTER(pFontAmbient, IFont);

		// Make a clone of the ambient font.
		pFontAmbient->Clone(&pFontNew);
		pFontAmbient->Release();
	}
	else
	{
		// Create the font.
		if (pFontDesc == NULL)
			pFontDesc = &_afxFontDescDefault;

		if (FAILED(::OleCreateFontIndirect((LPFONTDESC)pFontDesc, IID_IFont,
				(LPVOID *)&pFontNew)))
			pFontNew = NULL;
	}

	// Setup advisory connection and find dispatch interface.
	if (pFontNew != NULL)
		SetFont(pFontNew);
}

BOOL AFXAPI _AfxIsSameFont(CFontHolder& font, const FONTDESC* pFontDesc,
	LPFONTDISP pFontDispAmbient)
{
	if (font.m_pFont == NULL)
		return FALSE;

	BOOL bSame = FALSE;

	if (pFontDispAmbient != NULL)
	{
		LPFONT pFontAmbient;
		if (SUCCEEDED(pFontDispAmbient->QueryInterface(IID_IFont,
			(LPVOID*)&pFontAmbient)))
		{
			ASSERT_POINTER(pFontAmbient, IFont);
			bSame = pFontAmbient->IsEqual(font.m_pFont) == S_OK;
			pFontAmbient->Release();
		}
	}
	else
	{
		if (pFontDesc == NULL)
			pFontDesc = &_afxFontDescDefault;

		bSame = TRUE;
		BOOL bFlag;

		font.m_pFont->get_Italic(&bFlag);
		bSame = (bFlag == pFontDesc->fItalic);

		if (bSame)
		{
			font.m_pFont->get_Underline(&bFlag);
			bSame = (bFlag == pFontDesc->fUnderline);
		}

		if (bSame)
		{
			font.m_pFont->get_Strikethrough(&bFlag);
			bSame = (bFlag == pFontDesc->fStrikethrough);
		}

		if (bSame)
		{
			short sCharset;
			font.m_pFont->get_Charset(&sCharset);
			bSame = (sCharset == pFontDesc->sCharset);
		}

		if (bSame)
		{
			short sWeight;
			font.m_pFont->get_Weight(&sWeight);
			bSame = (sWeight == pFontDesc->sWeight);
		}

		if (bSame)
		{
			CURRENCY cy;
			font.m_pFont->get_Size(&cy);
			bSame = (memcmp(&cy, &pFontDesc->cySize, sizeof(CURRENCY)) == 0);
		}

		if (bSame)
		{
			BSTR bstrName;
			font.m_pFont->get_Name(&bstrName);
			CString strName1(bstrName);
			CString strName2(pFontDesc->lpstrName);
			bSame = (strName1 == strName2);
			SysFreeString(bstrName);
		}
	}

	return bSame;
}

HFONT CFontHolder::GetFontHandle()
{
	// Assume a screen DC for logical/himetric ratio.
	return GetFontHandle(afxData.cyPixelsPerInch, HIMETRIC_PER_INCH);
}

HFONT CFontHolder::GetFontHandle(long cyLogical, long cyHimetric)
{
	HFONT hFont = NULL;

	if ((m_pFont != NULL) &&
		SUCCEEDED(m_pFont->SetRatio(cyLogical, cyHimetric)) &&
		SUCCEEDED(m_pFont->get_hFont(&hFont)))
	{
		ASSERT(hFont != NULL);
	}

	return hFont;
}

CFont* CFontHolder::Select(CDC* pDC, long cyLogical, long cyHimetric)
{
	ASSERT_POINTER(pDC, CDC);

	HFONT hFont = NULL;

	if (m_pFont != NULL)
		hFont = GetFontHandle(cyLogical, cyHimetric);

	if (hFont != NULL)
	{
		if ((pDC->m_hAttribDC != pDC->m_hDC) &&
			(pDC->m_hAttribDC != NULL))
		{
			::SelectObject(pDC->m_hAttribDC, hFont);
		}

		return CFont::FromHandle((HFONT)::SelectObject(pDC->m_hDC, hFont));
	}

	return NULL;
}

void CFontHolder::QueryTextMetrics(LPTEXTMETRIC lptm)
{
	ASSERT(lptm != NULL);

	if (m_pFont != NULL)
	{
#if defined(_UNICODE) || defined(OLE2ANSI)
		// no conversion necessary
		m_pFont->QueryTextMetrics(lptm);
#else
		TEXTMETRICW tmw;
		m_pFont->QueryTextMetrics(&tmw);
		AfxTextMetricW2A(lptm, &tmw);
#endif
	}
	else
	{
		memset(lptm, 0, sizeof(TEXTMETRIC));
	}
}

LPFONTDISP CFontHolder::GetFontDispatch()
{
	LPFONTDISP pFontDisp = NULL;

	if ((m_pFont != NULL) &&
		SUCCEEDED(m_pFont->QueryInterface(IID_IFontDisp, (LPVOID*)&pFontDisp)))
	{
		ASSERT_POINTER(pFontDisp, IFontDisp);
	}

	return pFontDisp;
}

void CFontHolder::SetFont(LPFONT pFontNew)
{
	ASSERT_NULL_OR_POINTER(pFontNew, IFont);

	if (m_pFont != NULL)
		ReleaseFont();

	m_pFont = pFontNew;

	if (m_pNotify != NULL)
	{
		AfxConnectionAdvise(m_pFont, IID_IPropertyNotifySink, m_pNotify,
			FALSE, &m_dwConnectCookie);
	}
}

BOOL CFontHolder::GetDisplayString(CString& strValue)
{
	return strValue.LoadString(AFX_IDS_DISPLAYSTRING_FONT);
}

/////////////////////////////////////////////////////////////////////////////
// Force any extra compiler-generated code into AFX_INIT_SEG

#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif
