Click here to Skip to main content
15,885,546 members
Articles / Desktop Programming / MFC

A Simple HTML Drawing Class

Rate me:
Please Sign up or sign in to vote.
4.72/5 (27 votes)
5 Aug 20034 min read 166.1K   5.3K   67  
Drawing HTML text onto a device context
// HTMLDrawer.cpp: implementation of the CHTMLDrawer class.
//
//////////////////////////////////////////////////////////////////////
// (c) Jerome Sopocko 2003
// this code worked last time I saw it
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "HTMLDrawer.h"

#include "HTMLAtom.h"

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

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CHTMLDrawer::CHTMLDrawer()
{

}

CHTMLDrawer::~CHTMLDrawer()
{

}

/////////////////////////////////////////////////////////////
// DrawText
/////////////////////////////////////////////////////////////
// Parameters:
// pDC : Device context
// strText: Text to be drawn
// fntDefault : Default font to be used
// rctPosition : Rectangle in which the text is to be drawn
// nJustification: 0 (left) or 1 (centered) or 2 (right)
/////////////////////////////////////////////////////////////
void CHTMLDrawer::DrawText(CDC * pDC, const CString & strText,const CHTMLFont & fntDefault,CRect & rctPosition,short nJustification)
{
	// Parse the text to break into atoms having the same settings
	CObArray arrAtoms;
	ParseHTMLText(strText,fntDefault,arrAtoms);

	// If no text return
	if ( arrAtoms.GetSize() == 0 )
		return;

	// If only one atom = > draw it with CDC::DrawText
	if ( arrAtoms.GetSize() == 1 )
	{
		CHTMLAtom * pAtom = (CHTMLAtom *) arrAtoms.GetAt(0);

		// Select the font
		CFont* pFont = pAtom->GetHTMLFont().GetFont(pDC);
		CFont* pOldFont =pDC->SelectObject(pFont);
		COLORREF rgbOldColor  = pDC->SetTextColor(pAtom->GetHTMLFont().GetColor());
		pDC->SetBkMode(TRANSPARENT);

		// Calculate the size of the text
		CSize sizText = pDC->GetTextExtent(pAtom->GetText());

		int nX;
		switch (nJustification)
		{
		case 0:
			nX = 0;
			break;
		case 1:
			nX = (rctPosition.right - sizText.cy)/2;
			break;
		case 2:
			nX = rctPosition.right - sizText.cy - 1;
			break;
		}

		// If one line of text fits
		bool isOneLine = false;;
		if ( ( sizText.cx < rctPosition.Width() ) && (pAtom->GetText().Find(_T("\n")) == -1 ) )
		{
			int nY = rctPosition.top + (rctPosition.Height()-sizText.cy)/2;
			pDC->DrawText(pAtom->GetText(),CRect(rctPosition.left+nX,nY,rctPosition.right+nX,rctPosition.bottom),DT_LEFT |DT_NOPREFIX |DT_SINGLELINE);
			isOneLine = true;
		}

		// Reset DC original settings
		pDC->SelectObject(pOldFont);
		pDC->SetTextColor(rgbOldColor);
		delete pFont;

		if ( isOneLine )
		{
			CHTMLAtom::DeleteArray(arrAtoms);
			return;
		}
	}

	// Break into smaller atoms according to end of line
	CObArray arrDisplayAtoms;
	BreakIntoLines(pDC,arrAtoms,arrDisplayAtoms,rctPosition);

	CHTMLAtom::DeleteArray(arrAtoms);

	// Find the lowest position to center vertically
	int nLowest = 0;
	for ( int nAtom = 0; nAtom < arrDisplayAtoms.GetSize(); nAtom++)
	{
		CHTMLAtom * pAtom = (CHTMLAtom *) arrDisplayAtoms.GetAt(nAtom);
		if ( pAtom->GetPosition().bottom > nLowest )
			nLowest = pAtom->GetPosition().bottom;
	}

	int nShiftVertically = 0;
	if ( nLowest < rctPosition.Height() )
		nShiftVertically = (rctPosition.Height()-nLowest) / 2;

	// Display all atoms
	DrawAtoms(pDC,arrDisplayAtoms,nShiftVertically,nJustification,rctPosition.right);
	CHTMLAtom::DeleteArray(arrDisplayAtoms);
}


void CHTMLDrawer::ParseHTMLText(const CString & strSource,const CHTMLFont & fntDefault,CObArray & arrAtoms)
{
	CString strText(strSource);
	CHTMLFont fntCurrent(fntDefault);

	CObArray arrFontStack;
	int nTagStart;
	while ( (nTagStart = strText.Find('<')) != -1 )
	{
		int nTagEnd = strText.Find('>',nTagStart);
		if ( nTagEnd == -1 )
		{
			break;
		}
		AddText(arrAtoms,strText.Left(nTagStart),fntCurrent);

		CString strTag=strText.Mid(nTagStart+1,nTagEnd-nTagStart-1);
		bool isNewLine=false;
		UpdatePoliceAccordingToTag(strTag,fntCurrent,arrFontStack,isNewLine);
		strText = strText.Mid(nTagEnd+1);
		if ( isNewLine )
			AddText(arrAtoms,_T("\r\n"),fntCurrent);
	}
	if ( !strText.IsEmpty() )
	{
		AddText(arrAtoms,strText,fntCurrent);
	}
	CHTMLFont::DeleteArray(arrFontStack);
}

void CHTMLDrawer::AddText(CObArray & arrAtoms,const CString & strCodedText,CHTMLFont & polCurrent)
{
	if ( !strCodedText.IsEmpty() )
	{
		// Translate &quot; &lt; &gt; and &amp;
		CString strText(strCodedText);

		int nTagStart;
		while ( (nTagStart = strText.Find('&')) != -1 )
		{
			int nTagEnd = strText.Find(';',nTagStart);
			if ( nTagEnd == -1 )
			{
				break;
			}
			CString strEnd=strText.Mid(nTagEnd+1);
			CString strTag=strText.Mid(nTagStart+1,nTagEnd-nTagStart-1);
			strText=strText.Left(nTagStart);
			if ( strTag.CompareNoCase(_T("quot")) == 0 )
				strText+='\'';
			else if ( strTag.CompareNoCase(_T("lt")) == 0 )
				strText+='<';
			else if ( strTag.CompareNoCase(_T("gt")) == 0 )
				strText+='>';
			else if ( strTag.CompareNoCase(_T("amp")) == 0 )
				strText+='&';
			strText+=strEnd;
		}

		CHTMLAtom * pAtom=new CHTMLAtom;
		pAtom->SetText(strText);
		pAtom->SetHTMLFont(polCurrent);
		arrAtoms.Add(pAtom);
	}
}

void CHTMLDrawer::UpdatePoliceAccordingToTag(CString & strTag,CHTMLFont & polCurrent,CObArray & arrFontStack,bool & isNewLine)
{
	strTag.TrimLeft();
	strTag.TrimRight();
	if ( strTag.CompareNoCase(_T("b")) == 0 )
	{
		polCurrent.SetBold(true);
		return;
	}
	else if ( strTag.CompareNoCase(_T("strong")) == 0 )
	{
		polCurrent.SetBold(true);
		return;
	}
	else if ( strTag.CompareNoCase(_T("/b")) == 0 )
	{
		polCurrent.SetBold(false);
		return;
	}
	else if ( strTag.CompareNoCase(_T("/strong")) == 0 )
	{
		polCurrent.SetBold(false);
		return;
	}
	else if ( strTag.CompareNoCase(_T("i")) == 0 )
	{
		polCurrent.SetItalic(true);
		return;
	}
	else if ( strTag.CompareNoCase(_T("/i")) == 0 )
	{
		polCurrent.SetItalic(false);
		return;
	}
	else if ( strTag.CompareNoCase(_T("u")) == 0 )
	{
		polCurrent.SetUnderline(true);
		return;
	}
	else if ( strTag.CompareNoCase(_T("/u")) == 0 )
	{
		polCurrent.SetUnderline(false);
		return;
	}
	else if ( strTag.CompareNoCase(_T("br")) == 0 )
	{
		isNewLine = true;
		return;
	}
	else if ( strTag.Left(4).CompareNoCase(_T("font")) == 0 )
	{
		// Store previous police and color in stack
		arrFontStack.Add((CObject *) new CHTMLFont(polCurrent));

		CString strInfo = strTag.Mid(4);
		while ( true )
		{
			int nPos = strInfo.Find(_T('='));
			if ( nPos == -1 )
				break;

			// Find the name of the property
			CString strName = strInfo.Left(nPos);
			strName.TrimLeft();
			strName.TrimRight();

			// Find the start of the value
			strInfo = strInfo.Mid(nPos+1);
			while ( strInfo[0] == ' ')
				strInfo = strInfo.Mid(1);

			// Find the value
			CString strValue;
			if ( strInfo[0] == '"' )
			{
				nPos = strInfo.Find('"',1);
				if ( nPos != -1 )
				{
					strValue=strInfo.Mid(1,nPos-1);
					strInfo = strInfo.Mid(nPos+1);
				}
			}
			else
			{
				nPos = strInfo.Find(' ');
				if ( nPos != -1 )
				{
					strValue=strInfo.Left(nPos);
					strInfo = strInfo.Mid(nPos+1);
				}
				else
				{
					strValue=strInfo;
					strInfo.Empty();
				}
			}
			if ( !strValue.IsEmpty() )
			{

				// Update current police
				if ( strName.CompareNoCase(_T("face")) == 0 )
				{
					polCurrent.SetName(strValue);
				}
				else if ( strName.CompareNoCase(_T("size")) == 0 )
				{
					int nSizeBefore = polCurrent.GetHTMLSize();
					int nSize;
					if ( strValue[0] == '+' )
					{
						nSize= nSizeBefore + ToLong(strValue.Mid(1));
					}
					else if ( strValue[0] == '-' )
					{
						nSize= nSizeBefore - ToLong(strValue.Mid(1));
					}
					else
					{
						nSize= ToLong(strValue);
					}
					polCurrent.SetHTMLSize(nSize);
					polCurrent.SetSize(polCurrent.GetSize()/CHTMLFont::GetHTMLSizeCoeffient(nSizeBefore) * CHTMLFont::GetHTMLSizeCoeffient(nSize));
				}
				else if ( strName.CompareNoCase(_T("color")) == 0 )
				{
					// Try to find the color
					if ( strValue.CompareNoCase(_T("Light")) < 0 )
					{
						if ( strValue.CompareNoCase(_T("Deep")) < 0 )
						{
							if ( strValue.CompareNoCase(_T("Dark")) < 0 )
							{
								if ( strValue.CompareNoCase(_T("AliceBlue")) == 0 )
									strValue = _T("#F0F8FF");
								else if ( strValue.CompareNoCase(_T("AntiqueWhite")) == 0 )
									strValue = _T("#FAEBD7");
								else if ( strValue.CompareNoCase(_T("Aqua")) == 0 )
									strValue = _T("#00FFFF");
								else if ( strValue.CompareNoCase(_T("Aquamarine")) == 0 )
									strValue = _T("#7FFFD4");
								else if ( strValue.CompareNoCase(_T("Azure")) == 0 )
									strValue = _T("#F0FFFF");
								else if ( strValue.CompareNoCase(_T("Beige")) == 0 )
									strValue = _T("#F5F5DC");
								else if ( strValue.CompareNoCase(_T("Black")) == 0 )
									strValue = _T("#000000");
								else if ( strValue.CompareNoCase(_T("BlanchedAlmond")) == 0 )
									strValue = _T("#FFEBCD");
								else if ( strValue.CompareNoCase(_T("Blue")) == 0 )
									strValue = _T("#0000FF");
								else if ( strValue.CompareNoCase(_T("BlueViolet")) == 0 )
									strValue = _T("#8A2BE2");
								else if ( strValue.CompareNoCase(_T("Brown")) == 0 )
									strValue = _T("#A52A2A");
								else if ( strValue.CompareNoCase(_T("Bisque")) == 0 )
									strValue = _T("#FFE4C4");
								else if ( strValue.CompareNoCase(_T("BurlyWood")) == 0 )
									strValue = _T("#DEB887");
								else if ( strValue.CompareNoCase(_T("CadetBlue")) == 0 )
									strValue = _T("#5F9EA0");
								else if ( strValue.CompareNoCase(_T("Chartreuse")) == 0 )
									strValue = _T("#7FFF00");
								else if ( strValue.CompareNoCase(_T("Chocolate")) == 0 )
									strValue = _T("#D2691E");
								else if ( strValue.CompareNoCase(_T("Coral")) == 0 )
									strValue = _T("#FF7F50");
								else if ( strValue.CompareNoCase(_T("CornflowerBlue")) == 0 )
									strValue = _T("#6495ED");
								else if ( strValue.CompareNoCase(_T("CornSilk")) == 0 )
									strValue = _T("#FFF8DC");
								else if ( strValue.CompareNoCase(_T("Crimson")) == 0 )
									strValue = _T("#DC143C");
								else if ( strValue.CompareNoCase(_T("Cyan")) == 0 )
									strValue = _T("#00FFFF");
							}
							else
							{
								if ( strValue.CompareNoCase(_T("DarkBlue")) == 0 )
									strValue = _T("#00008B");
								else if ( strValue.CompareNoCase(_T("DarkCyan")) == 0 )
									strValue = _T("#008B8B");
								else if ( strValue.CompareNoCase(_T("DarkGoldenrod")) == 0 )
									strValue = _T("#B8860B");
								else if ( strValue.CompareNoCase(_T("DarkGray")) == 0 )
									strValue = _T("#A9A9A9");
								else if ( strValue.CompareNoCase(_T("DarkGreen")) == 0 )
									strValue = _T("#006400");
								else if ( strValue.CompareNoCase(_T("DarkKhaki")) == 0 )
									strValue = _T("#BDB76B");
								else if ( strValue.CompareNoCase(_T("DarkMagenta")) == 0 )
									strValue = _T("#8B008B");
								else if ( strValue.CompareNoCase(_T("DarkOliveGreen")) == 0 )
									strValue = _T("#556B2F");
								else if ( strValue.CompareNoCase(_T("DarkOrange")) == 0 )
									strValue = _T("#FF8C00");
								else if ( strValue.CompareNoCase(_T("DarkOrchid")) == 0 )
									strValue = _T("#9932CC");
								else if ( strValue.CompareNoCase(_T("DarkRed")) == 0 )
									strValue = _T("#8B0000");
								else if ( strValue.CompareNoCase(_T("DarkSalmon")) == 0 )
									strValue = _T("#E9967A");
								else if ( strValue.CompareNoCase(_T("DarkSeaGreen")) == 0 )
									strValue = _T("#8FBC8F");
								else if ( strValue.CompareNoCase(_T("DarkSlateBlue")) == 0 )
									strValue = _T("#483D8B");
								else if ( strValue.CompareNoCase(_T("DarkSlateGray")) == 0 )
									strValue = _T("#2F4F4F");
								else if ( strValue.CompareNoCase(_T("DarkTurquoise")) == 0 )
									strValue = _T("#00CED1");
								else if ( strValue.CompareNoCase(_T("DarkViolet")) == 0 )
									strValue = _T("#9400D3");
							}
						}
						else
						{
							if ( strValue.CompareNoCase(_T("DeepPink")) == 0 )
								strValue = _T("#FF1493");
							else if ( strValue.CompareNoCase(_T("DeepSkyBlue")) == 0 )
								strValue = _T("#00BFFF");
							else if ( strValue.CompareNoCase(_T("DimGray")) == 0 )
								strValue = _T("#696969");
							else if ( strValue.CompareNoCase(_T("DodgerBlue")) == 0 )
								strValue = _T("#1E90FF");
							else if ( strValue.CompareNoCase(_T("FireBrick")) == 0 )
								strValue = _T("#B22222");
							else if ( strValue.CompareNoCase(_T("FloralWhite")) == 0 )
								strValue = _T("#FFFAF0");
							else if ( strValue.CompareNoCase(_T("ForestGreen")) == 0 )
								strValue = _T("#228B22");
							else if ( strValue.CompareNoCase(_T("Fuchsia")) == 0 )
								strValue = _T("#FF00FF");
							else if ( strValue.CompareNoCase(_T("Gainsboro")) == 0 )
								strValue = _T("#DCDCDC");
							else if ( strValue.CompareNoCase(_T("GhostWhite")) == 0 )
								strValue = _T("#F8F8FF");
							else if ( strValue.CompareNoCase(_T("Gold")) == 0 )
								strValue = _T("#FFD700");
							else if ( strValue.CompareNoCase(_T("Goldenrod")) == 0 )
								strValue = _T("#DAA520");
							else if ( strValue.CompareNoCase(_T("Gray")) == 0 )
								strValue = _T("#808080");
							else if ( strValue.CompareNoCase(_T("Green")) == 0 )
								strValue = _T("#008000");
							else if ( strValue.CompareNoCase(_T("GreenYellow")) == 0 )
								strValue = _T("#ADFF2F");
							else if ( strValue.CompareNoCase(_T("Honeydew")) == 0 )
								strValue = _T("#F0FFF0");
							else if ( strValue.CompareNoCase(_T("HotPink")) == 0 )
								strValue = _T("#FF69B4");
							else if ( strValue.CompareNoCase(_T("IndianRed")) == 0 )
								strValue = _T("#CD5C5C");
							else if ( strValue.CompareNoCase(_T("Indigo")) == 0 )
								strValue = _T("#4B0082");
							else if ( strValue.CompareNoCase(_T("Ivory")) == 0 )
								strValue = _T("#FFFFF0");
							else if ( strValue.CompareNoCase(_T("Khaki")) == 0 )
								strValue = _T("#F0E86C");
							else if ( strValue.CompareNoCase(_T("Lavender")) == 0 )
								strValue = _T("#E6E6FA");
							else if ( strValue.CompareNoCase(_T("LavenderBlush")) == 0 )
								strValue = _T("#FFF0F5");
							else if ( strValue.CompareNoCase(_T("LawnGreen")) == 0 )
								strValue = _T("#7CFC00");
							else if ( strValue.CompareNoCase(_T("LemonChiffon")) == 0 )
								strValue = _T("#FFFACD");
						}
					}
					else
					{
						if ( strValue.CompareNoCase(_T("Pale")) < 0 )
						{
							if ( strValue.CompareNoCase(_T("Medium")) < 0 )
							{
								if ( strValue.CompareNoCase(_T("LightBlue")) == 0 )
									strValue = _T("#ADD8E6");
								else if ( strValue.CompareNoCase(_T("LightCoral")) == 0 )
									strValue = _T("#F08080");
								else if ( strValue.CompareNoCase(_T("LightCyan")) == 0 )
									strValue = _T("#E0FFFF");
								else if ( strValue.CompareNoCase(_T("LightGoldenrodYellow")) == 0 )
									strValue = _T("#FAFAD2");
								else if ( strValue.CompareNoCase(_T("LightGray")) == 0 )
									strValue = _T("#D3D3D3");
								else if ( strValue.CompareNoCase(_T("LightGreen")) == 0 )
									strValue = _T("#90EE90");
								else if ( strValue.CompareNoCase(_T("LightPink")) == 0 )
									strValue = _T("#FFB6C1");
								else if ( strValue.CompareNoCase(_T("LightSalmon")) == 0 )
									strValue = _T("#FFA07A");
								else if ( strValue.CompareNoCase(_T("LightSkyBlue")) == 0 )
									strValue = _T("#87CEFA");
								else if ( strValue.CompareNoCase(_T("LightSeaGreen")) == 0 )
									strValue = _T("#20B2AA");
								else if ( strValue.CompareNoCase(_T("LightSlateGray")) == 0 )
									strValue = _T("#778899");
								else if ( strValue.CompareNoCase(_T("LightSteelBlue")) == 0 )
									strValue = _T("#B0C4DE");
								else if ( strValue.CompareNoCase(_T("LightYellow")) == 0 )
									strValue = _T("#FFFFE0");
								else if ( strValue.CompareNoCase(_T("Lime")) == 0 )
									strValue = _T("#00FF00");
								else if ( strValue.CompareNoCase(_T("LimeGreen")) == 0 )
									strValue = _T("#32CD32");
								else if ( strValue.CompareNoCase(_T("Linen")) == 0 )
									strValue = _T("#FAF0E6");
								else if ( strValue.CompareNoCase(_T("Magenta")) == 0 )
									strValue = _T("#FF00FF");
								else if ( strValue.CompareNoCase(_T("Maroon")) == 0 )
									strValue = _T("#800000");
							}
							else
							{
								if ( strValue.CompareNoCase(_T("MediumAquamarine")) == 0 )
									strValue = _T("#66CDAA");
								else if ( strValue.CompareNoCase(_T("MediumBlue")) == 0 )
									strValue = _T("#0000CD");
								else if ( strValue.CompareNoCase(_T("MediumOrchid")) == 0 )
									strValue = _T("#BA55D3");
								else if ( strValue.CompareNoCase(_T("MediumPurple")) == 0 )
									strValue = _T("#9370DB");
								else if ( strValue.CompareNoCase(_T("MediumSeaGreen")) == 0 )
									strValue = _T("#3CB371");
								else if ( strValue.CompareNoCase(_T("MediumSlateBlue")) == 0 )
									strValue = _T("#7B68EE");
								else if ( strValue.CompareNoCase(_T("MediumSpringGreen")) == 0 )
									strValue = _T("#00FA9A");
								else if ( strValue.CompareNoCase(_T("MediumTurquoise")) == 0 )
									strValue = _T("#48D1CC");
								else if ( strValue.CompareNoCase(_T("MediumVioletRed")) == 0 )
									strValue = _T("#C71585");
								else if ( strValue.CompareNoCase(_T("MidnightBlue")) == 0 )
									strValue = _T("#191970");
								else if ( strValue.CompareNoCase(_T("MintCream")) == 0 )
									strValue = _T("#F5FFFA");
								else if ( strValue.CompareNoCase(_T("MistyRose")) == 0 )
									strValue = _T("#FFE4E1");
								else if ( strValue.CompareNoCase(_T("Mocassin")) == 0 )
									strValue = _T("#FFE4B5");
								else if ( strValue.CompareNoCase(_T("NavajoWhite")) == 0 )
									strValue = _T("#FFDEAD");
								else if ( strValue.CompareNoCase(_T("Navy")) == 0 )
									strValue = _T("#000080");
								else if ( strValue.CompareNoCase(_T("OldLace")) == 0 )
									strValue = _T("#FDF5E6");
								else if ( strValue.CompareNoCase(_T("Olive")) == 0 )
									strValue = _T("#808000");
								else if ( strValue.CompareNoCase(_T("OliveDrab")) == 0 )
									strValue = _T("#6B8E23");
								else if ( strValue.CompareNoCase(_T("Orange")) == 0 )
									strValue = _T("#FFA500");
								else if ( strValue.CompareNoCase(_T("OrangeRed")) == 0 )
									strValue = _T("#FF4500");
								else if ( strValue.CompareNoCase(_T("Orchid")) == 0 )
									strValue = _T("#DA70D6");
							}
						}
						else
						{
							if ( strValue.CompareNoCase(_T("Sea")) < 0 )
							{
								if ( strValue.CompareNoCase(_T("PaleGoldenrod")) == 0 )
									strValue = _T("#EEE8AA");
								else if ( strValue.CompareNoCase(_T("PaleGreen")) == 0 )
									strValue = _T("#98FB98");
								else if ( strValue.CompareNoCase(_T("PaleTurquoise")) == 0 )
									strValue = _T("#AFEEEE");
								else if ( strValue.CompareNoCase(_T("PaleVioletRed")) == 0 )
									strValue = _T("#DB7093");
								else if ( strValue.CompareNoCase(_T("PapayaWhip")) == 0 )
									strValue = _T("#FFEFD5");
								else if ( strValue.CompareNoCase(_T("PeachPuff")) == 0 )
									strValue = _T("#FFDAB9");
								else if ( strValue.CompareNoCase(_T("Peru")) == 0 )
									strValue = _T("#CD853F");
								else if ( strValue.CompareNoCase(_T("Pink")) == 0 )
									strValue = _T("#FFC0CB");
								else if ( strValue.CompareNoCase(_T("Plum")) == 0 )
									strValue = _T("#DDA0DD");
								else if ( strValue.CompareNoCase(_T("PowderBlue")) == 0 )
									strValue = _T("#B0E0E6");
								else if ( strValue.CompareNoCase(_T("Purple")) == 0 )
									strValue = _T("#800080");
								else if ( strValue.CompareNoCase(_T("Red")) == 0 )
									strValue = _T("#FF0000");
								else if ( strValue.CompareNoCase(_T("RosyBrown")) == 0 )
									strValue = _T("#BC8F8F");
								else if ( strValue.CompareNoCase(_T("RoyalBlue")) == 0 )
									strValue = _T("#4169E1");
								else if ( strValue.CompareNoCase(_T("SaddleBrown")) == 0 )
									strValue = _T("#8b4513");
								else if ( strValue.CompareNoCase(_T("Salmon")) == 0 )
									strValue = _T("#FA8072");
								else if ( strValue.CompareNoCase(_T("SandyBrown")) == 0 )
									strValue = _T("#F4A460");
							}
							else
							{
								if ( strValue.CompareNoCase(_T("SeaGreen")) == 0 )
									strValue = _T("#2E8B57");
								else if ( strValue.CompareNoCase(_T("SeaShell")) == 0 )
									strValue = _T("#FFF5EE");
								else if ( strValue.CompareNoCase(_T("Sienna")) == 0 )
									strValue = _T("#A0522D");
								else if ( strValue.CompareNoCase(_T("Silver")) == 0 )
									strValue = _T("#C0C0C0");
								else if ( strValue.CompareNoCase(_T("SpringGreen")) == 0 )
									strValue = _T("#00FF7F");
								else if ( strValue.CompareNoCase(_T("SkyBlue")) == 0 )
									strValue = _T("#87CEEB");
								else if ( strValue.CompareNoCase(_T("SlateBlue")) == 0 )
									strValue = _T("#6A5ACD");
								else if ( strValue.CompareNoCase(_T("SlateGray")) == 0 )
									strValue = _T("#708090");
								else if ( strValue.CompareNoCase(_T("Snow")) == 0 )
									strValue = _T("#FFFAFA");
								else if ( strValue.CompareNoCase(_T("SteelBlue")) == 0 )
									strValue = _T("#4682B4");
								else if ( strValue.CompareNoCase(_T("Tan")) == 0 )
									strValue = _T("#D2B48C");
								else if ( strValue.CompareNoCase(_T("Teal")) == 0 )
									strValue = _T("#008080");
								else if ( strValue.CompareNoCase(_T("Tomato")) == 0 )
									strValue = _T("#FF6347");
								else if ( strValue.CompareNoCase(_T("Turquoise")) == 0 )
									strValue = _T("#40E0D0");
								else if ( strValue.CompareNoCase(_T("Thistle")) == 0 )
									strValue = _T("#D8BFD8");
								else if ( strValue.CompareNoCase(_T("Violet")) == 0 )
									strValue = _T("#EE82EE");
								else if ( strValue.CompareNoCase(_T("Wheat")) == 0 )
									strValue = _T("#F5DEB3");
								else if ( strValue.CompareNoCase(_T("White")) == 0 )
									strValue = _T("#FFFFFF");
								else if ( strValue.CompareNoCase(_T("WhiteSmoke")) == 0 )
									strValue = _T("#F5F5F5");
								else if ( strValue.CompareNoCase(_T("Yellow")) == 0 )
									strValue = _T("#FFFF00");
								else if ( strValue.CompareNoCase(_T("YellowGreen")) == 0 )
									strValue = _T("#9ACD32");
							}
						}
					}

					if ( strValue[0] == '#' )
					{
						strValue = strValue.Mid(1);
						if ( strValue.GetLength() < 6 )
						{
							CString strTemp;
							strTemp.Format(_T("%0*d%s"),6-strValue.GetLength(),0,strValue);
							strValue = strTemp;
						}
						polCurrent.SetColor(RGB(FromHex(strValue.Left(2)),FromHex(strValue.Mid(2,2)),FromHex(strValue.Mid(4,2))));
					}
				}
			}
		}
	}
	else if ( strTag.Left(5).CompareNoCase(_T("/font")) == 0 )
	{
		if ( arrFontStack.GetSize() >0 )
		{
			CHTMLFont * pFont = (CHTMLFont *) arrFontStack.GetAt(arrFontStack.GetSize()-1);
			polCurrent = *pFont;
			delete pFont;
			arrFontStack.SetSize(arrFontStack.GetSize()-1);
		}
	}
}

void CHTMLDrawer::BreakIntoLines(CDC * pDC,CObArray & arrAtoms,CObArray & arrDisplayAtoms,CRect & rctPosition)
{
	// Select the font
	CFont* pCurrentFont = NULL;
	CFont* pOldFont=NULL;

	int nY = rctPosition.top;
	int nX = rctPosition.left;
	int nXMax = rctPosition.right;
	int nStartLineAtom = 0;
	for ( int nAtom = 0; nAtom < arrAtoms.GetSize(); nAtom++)
	{
		CHTMLAtom * pAtom = (CHTMLAtom *) arrAtoms.GetAt(nAtom);

		// Find if there is a line break in the text
		bool isLineBreak = false;
		int nPos = pAtom->GetText().Find(_T("\r\n"));
		if ( nPos != -1 )
		{
			// Split this atom into 2
			CString strTextBefore = pAtom->GetText().Left(nPos);
			CString strTextAfter = pAtom->GetText().Mid(nPos+2);
			
			if ( !strTextAfter.IsEmpty() )
			{
				CHTMLAtom * pNewAtom = new CHTMLAtom;
				pNewAtom->SetText(strTextAfter);
				pNewAtom->SetHTMLFont(pAtom->GetHTMLFont());
				arrAtoms.InsertAt(nAtom+1,pNewAtom);
			}
			pAtom->SetText(strTextBefore);

			isLineBreak = true;
		}

		// Select the current font
		if ( pCurrentFont == NULL )
		{
			pCurrentFont = pAtom->GetHTMLFont().GetFont(pDC);
			pOldFont = pDC->SelectObject(pCurrentFont);
		}
		else
		{
			CFont * pNewFont = pAtom->GetHTMLFont().GetFont(pDC);
			pDC->SelectObject(pNewFont);
			delete pCurrentFont;
			pCurrentFont = pNewFont;
		}

		// Find the size of the text
		CString strTextToWrite = pAtom->GetText();
		while ( !strTextToWrite.IsEmpty() )
		{
			CSize sizText = pDC->GetTextExtent(strTextToWrite);

			// If it does not fit in the current line
			CString strPart=strTextToWrite;
			bool isCreateNewLine = false;
			while ( nX + sizText.cx >= nXMax)
			{
				RemoveLastWord(strPart);
				sizText = pDC->GetTextExtent(strPart);
				isCreateNewLine = true;
				if ( strPart.IsEmpty())
					break;
			}

			// If nothing fits, 
			if ( strPart.IsEmpty() )
			{
				// If the current line is empty
				if ( nStartLineAtom == arrDisplayAtoms.GetSize() )
				{
					// We have to break up anywhere
					strPart=strTextToWrite[0];
					for ( int nChar = 1; nChar < strTextToWrite.GetLength(); nChar++)
					{
						strPart+=strTextToWrite[nChar];
						sizText = pDC->GetTextExtent(strPart);
						if ( nX + sizText.cx > nXMax)
						{
							strPart = strPart.Left(strPart.GetLength()-1);
							break;
						}
					}
				}
			}

			if ( !strPart.IsEmpty() )
			{
				// We can draw strPart
				sizText = pDC->GetTextExtent(strPart);
				CRect rctTextPosition(nX,nY,nX+sizText.cx,nY+sizText.cy);
				
				CHTMLAtom * pDisplayAtom = new CHTMLAtom;
				pDisplayAtom->SetText(strPart);
				pDisplayAtom->SetHTMLFont(pAtom->GetHTMLFont());
				pDisplayAtom->SetPosition(rctTextPosition);
				arrDisplayAtoms.Add(pDisplayAtom);

				nX = rctTextPosition.right;
				strTextToWrite = strTextToWrite.Mid(strPart.GetLength());
			}

			if ( isCreateNewLine )
			{
				CreateNewLine(pDC,arrDisplayAtoms,nStartLineAtom,nY);
				nX=rctPosition.left;
				strTextToWrite.TrimLeft();
			}

			
		}
		if ( isLineBreak )
		{
			CreateNewLine(pDC,arrDisplayAtoms,nStartLineAtom,nY);
			nX=rctPosition.left;
		}
	}

	if ( pOldFont )
		pDC->SelectObject(pOldFont);
	delete pCurrentFont;
}

void CHTMLDrawer::CreateNewLine(CDC * pDC,CObArray & arrDisplayAtoms,int & nStartLineAtom,int & nY)
{
	// If no atom has been created for this line, create a dummy empty atom 
	if ( nStartLineAtom == arrDisplayAtoms.GetSize() )
	{
		CString strText=_T(" ");
		CSize sizText = pDC->GetTextExtent(strText);
		CRect rctTextPosition(0,nY,0+sizText.cx,nY+sizText.cy);

		CHTMLAtom * pDisplayAtom = new CHTMLAtom;
		pDisplayAtom->SetText(strText);
		pDisplayAtom->SetPosition(rctTextPosition);
		arrDisplayAtoms.Add(pDisplayAtom);

		nY=rctTextPosition.bottom+1;
		nStartLineAtom = arrDisplayAtoms.GetSize();

		return;
	}

	// Find the lowest atom on this line
	int nMaxBottom = nY;
	for ( int nAtom = nStartLineAtom; nAtom < arrDisplayAtoms.GetSize(); nAtom++)
	{
		CHTMLAtom * pLineAtom=(CHTMLAtom *) arrDisplayAtoms.GetAt(nAtom);
		if ( pLineAtom->GetPosition().bottom > nMaxBottom )
		{
			nMaxBottom = pLineAtom->GetPosition().bottom;
		}
	}
	// Align them to the lowest
	for ( nAtom = nStartLineAtom; nAtom < arrDisplayAtoms.GetSize(); nAtom++)
	{
		CHTMLAtom * pLineAtom=(CHTMLAtom *) arrDisplayAtoms.GetAt(nAtom);
		CRect rctPosition = pLineAtom->GetPosition();
		int nShift = nMaxBottom - rctPosition.bottom;
		rctPosition.top+=nShift;
		rctPosition.bottom+=nShift;
		pLineAtom->SetPosition(rctPosition);
	}
	nY=nMaxBottom+1;
	nStartLineAtom = arrDisplayAtoms.GetSize();
}

void CHTMLDrawer::RemoveLastWord(CString & strText)
{
	bool isOneCharRemoved = false;
	while ( strText.GetLength() != 0 )
	{
		TCHAR car = strText[strText.GetLength()-1];
		if ( ( ( car < 'a' ) || ( car > 'z' ) ) && ( ( car < 'A' ) || ( car > 'Z' ) ) )
		{
			if (!isOneCharRemoved )
				strText = strText.Left(strText.GetLength()-1);
			break;
		}
		strText = strText.Left(strText.GetLength()-1);
		isOneCharRemoved = true;
	}
}

void CHTMLDrawer::DrawAtoms(CDC * pDC,CObArray & arrDisplayAtoms,int nShiftVertically,short nJustification,int nRight)
{
	// Prepare the settings to be restored
	CFont* pCurrentFont = NULL;
	CFont* pOldFont;
	COLORREF rgbOldColor;
	pDC->SetBkMode(TRANSPARENT);

	int nCurrentY=-1;
	int nShiftX = 0;
	for ( int nAtom = 0; nAtom < arrDisplayAtoms.GetSize(); nAtom++)
	{
		CHTMLAtom * pAtom = (CHTMLAtom *) arrDisplayAtoms.GetAt(nAtom);

		// Select the font
		if ( pCurrentFont == NULL )
		{
			pCurrentFont = pAtom->GetHTMLFont().GetFont(pDC);
			pOldFont = pDC->SelectObject(pCurrentFont);
			rgbOldColor  = pDC->SetTextColor(pAtom->GetHTMLFont().GetColor());
		}
		else
		{
			CFont * pNewFont = pAtom->GetHTMLFont().GetFont(pDC);
			pDC->SelectObject(pNewFont);
			delete pCurrentFont;
			pCurrentFont = pNewFont;
			pDC->SetTextColor(pAtom->GetHTMLFont().GetColor());
		}

		if (nJustification != 0) 
		{
			// If we have changed line
			if ( nCurrentY != pAtom->GetPosition().top )
			{
				// Find the extent of the line
				nCurrentY = pAtom->GetPosition().top;
				int nMaxRight = pAtom->GetPosition().right;
				for ( int nFollowingAtom = nAtom+1; nFollowingAtom < arrDisplayAtoms.GetSize(); nFollowingAtom++)
				{
					CHTMLAtom * pFollowingAtom = (CHTMLAtom *) arrDisplayAtoms.GetAt(nFollowingAtom);
					if ( nCurrentY != pFollowingAtom->GetPosition().top )
						break;
					nMaxRight = pFollowingAtom->GetPosition().right;
				}
				if (nJustification == 1) 
					nShiftX = (nRight - nMaxRight)/2;
				else
					nShiftX = nRight - nMaxRight-1;
			}
		}

		// Draw the text
		CRect rctPosition(pAtom->GetPosition());
		rctPosition.top+=nShiftVertically;
		rctPosition.bottom+=nShiftVertically;
		rctPosition.left += nShiftX;
		rctPosition.right += nShiftX;
		pDC->DrawText(pAtom->GetText(),rctPosition,DT_LEFT |DT_NOPREFIX |DT_SINGLELINE);
	}

	// Restore the settings
	pDC->SelectObject(pOldFont);
	pDC->SetTextColor(rgbOldColor);
	delete pCurrentFont;
}


long CHTMLDrawer::FromHex(const CString & strHex)
{
	CString strHexa(strHex);
	strHexa.TrimRight();
	strHexa.TrimLeft();
	long nRes=0;
	long nBase=1;
	for ( int nChar = strHexa.GetLength()-1; nChar >= 0; nChar--)
	{
		switch (strHexa[nChar])
		{
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			nRes+=(strHexa[nChar]-'0')*nBase;
			break;
		case 'a':
		case 'b':
		case 'c':
		case 'd':
		case 'e':
		case 'f':
			nRes+=(10+strHexa[nChar]-'a')*nBase;
			break;
		case 'A':
		case 'B':
		case 'C':
		case 'D':
		case 'E':
		case 'F':
			nRes+=(10+strHexa[nChar]-'A')*nBase;
			break;
		}
		nBase*=16;
	}
	return nRes;
}


long CHTMLDrawer::ToLong(LPCTSTR lpszText)
{
	ASSERT(lpszText != NULL);

	while (*lpszText == ' ' || *lpszText == '\t')
		lpszText++;
	TCHAR chFirst = lpszText[0];
	long l;
	l = _tcstol(lpszText, (LPTSTR*)&lpszText, 10);

	if (l == 0 && chFirst != '0')
		return 0;   // could not convert

	while (*lpszText == ' ' || *lpszText == '\t')
		lpszText++;
	if (*lpszText != '\0')
		return 0;   // not terminated properly

	// all ok
	return l;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.


Written By
Web Developer
United Kingdom United Kingdom
Known as "The Wandering Geek", I have had to often change identities and countries due to the low quality level of the numerous software I have left behind.
Never wrote a software that did more than sorting 3 numbers which actually worked.
Hey but feel free to download my stuff!


Comments and Discussions