⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 htmlsectioncreator.cpp

📁 hl2 source code. Do not use it illegal.
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*----------------------------------------------------------------------
Copyright (c) 1998 Gipsysoft. All Rights Reserved.
Please see the file "licence.txt" for licencing details.
File:	HTMLSectionCreator.cpp
Owner:	russf@gipsysoft.com
Purpose:	Section creator for the HTML display.
----------------------------------------------------------------------*/
#include "stdafx.h"
#include <math.h>
#include <ImgLib.h>
#include "HTMLParse.h"
#include "HTMLSectionCreator.h"
#include "HTMLTextSection.h"
#include "HTMLImageSection.h"
#include "HTMLHorizontalRuleSection.h"
#include "HTMLSection.h"
#include "HTMLTableSection.h"
#include "tableLayout.h"
#include "defaults.h"

CHTMLSectionCreator::CHTMLSectionCreator( CHTMLSection *psect, CDrawContext &dc, int nTop, int nLeft, int nRight, COLORREF crBack, bool bMeasuring, int nZoomLevel )
	: m_psect( psect )
	, m_dc( dc )

	, m_nDefaultLeftMargin( nLeft )
	, m_nDefaultRightMargin( nRight )
	, m_crBack( crBack )
	, m_nLeftMargin( nLeft )
	, m_nRightMargin( nRight )

	, m_nYPos( nTop )
	, m_nTop( nTop )
	, m_nPreviousParaSpaceBelow( 0 )

	, m_nFirstShapeOnLine( 0 )
	, m_nNextYPos( nTop )
	, m_nWidth( 0 )
	, m_bMeasuring( bMeasuring )
	, m_nBaseLineShapeStartID( 0 )
	, m_nLowestBaseline( 0 )
	, m_algCurrentPargraph( CHTMLParse::algLeft )
	, m_nZoomLevel( nZoomLevel )
	, m_nXPos( 0 )
{
	m_dc.SelectFont( g_defaults.m_strFontName, GetFontSizeAsPixels( m_dc.GetSafeHdc(), g_defaults.m_nFontSize, m_nZoomLevel ), FW_NORMAL, false, false, false, g_defaults.m_cCharSet );
}

CHTMLSectionCreator::~CHTMLSectionCreator()
{

}


void CHTMLSectionCreator::CarriageReturn()
//
//	Recalcualtes the left and right margins for the current Y position and
//	moves the X position to the new left margin.
{
	if( GetCurrentShapeID() )
	{
		AdjustShapeBaselinesAndHorizontalAlignment();
	}
	m_nBaseLineShapeStartID = GetCurrentShapeID();

	m_nLeftMargin = m_nDefaultLeftMargin;
	while( m_stkLeftMargin.GetSize() )
	{
		MarginStackItem msi = m_stkLeftMargin.Top();
		if( msi.nYExpiry >= m_nYPos )
		{
			m_nLeftMargin = msi.nMargin;
			break;
		}
		else
		{
			m_stkLeftMargin.Pop();
		}
	}


	m_nRightMargin = m_nDefaultRightMargin;
	while( m_stkRightMargin.GetSize() )
	{
		MarginStackItem msi = m_stkRightMargin.Top();
		if( msi.nYExpiry >= m_nYPos )
		{
			m_nRightMargin = msi.nMargin;
			break;
		}
		else
		{
			m_stkRightMargin.Pop();
		}
	}
	m_nXPos = m_nLeftMargin;

	m_arrBaseline.RemoveAll();
	m_nLowestBaseline = 0;
	m_nFirstShapeOnLine = GetCurrentShapeID();

	//	If there is nothing in the margin stack, this is a good place for
	//	a page break.
	if( m_dc.IsPrinting() && m_nLeftMargin == m_nDefaultLeftMargin && m_nRightMargin == m_nDefaultRightMargin)
	{
		m_psect->AddBreakSection(GetCurrentShapeID());
	}

}


void CHTMLSectionCreator::Finished()
//
//	Signals the end fo the document.
{
	CarriageReturn();
	m_nYPos = m_nNextYPos;

	//
	//	Adjust the height of our document to take into account any images	there may be on the left or right
	//	of the document and that may be taller than we have left the document
	while( m_stkRightMargin.GetSize() )
	{
		MarginStackItem msi = m_stkRightMargin.Top();
		if( msi.nYExpiry > m_nYPos )
			m_nYPos = msi.nYExpiry;
		m_stkRightMargin.Pop();
	}

	while( m_stkLeftMargin.GetSize() )
	{
		MarginStackItem msi = m_stkLeftMargin.Top();
		if( msi.nYExpiry > m_nYPos )
			m_nYPos = msi.nYExpiry;
		m_stkLeftMargin.Pop();
	}
	if( m_dc.IsPrinting() )
		m_psect->AddBreakSection(GetCurrentShapeID());
}


void CHTMLSectionCreator::NewParagraph( int nSpaceAbove, int nSpaceBelow, CHTMLParse::Align alg )
//
//	New paragraph.
//	Add on the space below from the previous paragraph and the space above for this paragraph.
{
	CarriageReturn();
	m_nYPos = m_nNextYPos;
	if( m_nYPos != m_nTop )
	{
		m_nYPos += ( m_dc.GetCurrentFontHeight() * m_nPreviousParaSpaceBelow ) / 2;
		m_nYPos += ( m_dc.GetCurrentFontHeight() * nSpaceAbove ) / 2;
	}
	m_algCurrentPargraph = alg;
	m_nPreviousParaSpaceBelow = nSpaceBelow;
}


void CHTMLSectionCreator::AddTextPreformat( const StringClass &str, const HTMLFontDef &htmlfdef, COLORREF crFore, CHTMLSectionLink* pLink )
{
	FontDef fdef( htmlfdef.m_strFont, htmlfdef.m_nSize, htmlfdef.m_nWeight, htmlfdef.m_bItalic, htmlfdef.m_bUnderline, htmlfdef.m_bStrike, m_cCharSet );
	fdef.m_nSizePixels = GetFontSizeAsPixels( m_dc.GetSafeHdc(), htmlfdef.m_nSize, m_nZoomLevel );

	if( pLink )
		fdef.m_bUnderline = true;

	m_dc.SelectFont( fdef );

	LPCTSTR pcszTextLocal = str;
	LPCTSTR pcszPrevious = str;
	while( 1 )
	{
		if( *pcszTextLocal == '\r' || *pcszTextLocal == '\n' || *pcszTextLocal == '\000' )
		{
			const UINT uLength = pcszTextLocal - pcszPrevious;
			const CSize size( m_dc.GetTextExtent( pcszPrevious, uLength ), m_dc.GetCurrentFontHeight() );

			CHTMLTextSection *pText = new CHTMLTextSection( m_psect, pcszPrevious, uLength, fdef, crFore );
			pText->Set( m_nXPos, m_nYPos, m_nXPos + size.cx, m_nYPos + size.cy );

			AddBaseline( m_dc.GetCurrentFontBaseline() );

			CarriageReturn();
			m_nYPos = m_nNextYPos;

			if( *pcszTextLocal == '\000' )
			{
				break;
			}

			if( *pcszTextLocal == '\r' && *( pcszTextLocal + 1 ) == '\n' )
			{
				*pcszTextLocal++;
			}
			pcszPrevious = pcszTextLocal + 1;
		}
		*pcszTextLocal++;
	}
}


void CHTMLSectionCreator::AddText( const StringClass &str, const HTMLFontDef &htmlfdef, COLORREF crFore, CHTMLSectionLink* pLink )
{
	FontDef fdef( htmlfdef.m_strFont, htmlfdef.m_nSize, htmlfdef.m_nWeight, htmlfdef.m_bItalic, htmlfdef.m_bUnderline, htmlfdef.m_bStrike, m_cCharSet );
	fdef.m_nSizePixels = GetFontSizeAsPixels( m_dc.GetSafeHdc(), htmlfdef.m_nSize, m_nZoomLevel );

	if( pLink )
		fdef.m_bUnderline = true;

	m_dc.SelectFont( fdef );

	const int nCurrentFontHeight = m_dc.GetCurrentFontBaseline();

	/*
		try the text to see if it fits.
			if it does then simply create a new object and bump along the XPos
			if it does not then create an object with the least amount of data to fit
				create a new line (CarriageReturn) and try again.
	*/
	LPCTSTR pcszTextLocal = str;
	LPCTSTR pcszPrevious = str;
	CSize size;
	bool bDone = false;
	while( !bDone )
	{
		CHTMLTextSection *pText = NULL;

		//	richg - 19990224 - Altered to indicate the the CDrawContext whether or not
		//	we are at the beginning of a line.
		if( m_dc.GetTextFitWithWordWrap( m_nRightMargin - m_nXPos, pcszTextLocal, size, (bool)(m_nXPos == m_nLeftMargin) ) )
		{
			pText = new CHTMLTextSection( m_psect, pcszPrevious, pcszTextLocal - pcszPrevious, fdef, crFore );
			pText->Set( m_nXPos, m_nYPos, m_nXPos + size.cx, m_nYPos + size.cy );
			m_nXPos+=size.cx;
			if( htmlfdef.m_nSup )
			{
				AddBaseline( nCurrentFontHeight + htmlfdef.m_nSup * nCurrentFontHeight / 3 );
			}
			else if( htmlfdef.m_nSub )
			{
				AddBaseline( nCurrentFontHeight - htmlfdef.m_nSub * nCurrentFontHeight / 3 );
			}
			else
			{
				AddBaseline( nCurrentFontHeight );
			}
			bDone = true;
		}
		else
		{
			if( pcszTextLocal - pcszPrevious > 0 && ( m_nLeftMargin == m_nXPos || _istspace( *pcszTextLocal ) ) )
			{
				pText = new CHTMLTextSection( m_psect, pcszPrevious, pcszTextLocal - pcszPrevious, fdef, crFore );
				pText->Set( m_nXPos, m_nYPos, m_nXPos + size.cx, m_nYPos + size.cy );
				if( htmlfdef.m_nSup )
				{
					AddBaseline( nCurrentFontHeight + htmlfdef.m_nSup * nCurrentFontHeight / 3 );
				}
				else if( htmlfdef.m_nSub )
				{
					AddBaseline( nCurrentFontHeight - htmlfdef.m_nSub * nCurrentFontHeight / 3 );
				}
				else
				{
					AddBaseline( nCurrentFontHeight );
				}
			}
			else
			{
				pcszTextLocal = pcszPrevious;
			}
			CarriageReturn();
			m_nYPos = m_nNextYPos;

			//	Skip over trailing spaces
			while( *pcszTextLocal && _istspace( *pcszTextLocal ) ) pcszTextLocal++;
			pcszPrevious = pcszTextLocal;
		}

		if( pText && pLink )
		{
			pText->SetAsLink( pLink );
		}
	}
}


int CHTMLSectionCreator::GetCurrentShapeID() const
{
	return m_psect->GetSectionCount();
}


void CHTMLSectionCreator::AddBaseline( int nBaseline )
{
	UINT nIndex = GetCurrentShapeID() - m_nBaseLineShapeStartID;
	while( nIndex > m_arrBaseline.GetSize() )
		m_arrBaseline.Add( -1 );

	m_arrBaseline[ nIndex - 1 ] = nBaseline;
	if( nBaseline > m_nLowestBaseline )
	{
		m_nLowestBaseline = nBaseline;
	}
}


int CHTMLSectionCreator::GetBaseline( int nShape ) const
{
	// richg - Made this a little more tolerant of error.
	if (nShape < m_nBaseLineShapeStartID)
		return -1;
	const UINT index = nShape - m_nBaseLineShapeStartID;
	if( index < m_arrBaseline.GetSize())
	{
		return m_arrBaseline[ index ];
	}
	return -1;
}


void CHTMLSectionCreator::AdjustShapeBaselinesAndHorizontalAlignment()
//
//	Adjust the shapes baselines to allow for different heights and styles of text
{
	int nHorizontalDelta = 0;

	//
	//	Horizontally align the shapes.
	//
	//	Get the horizontal extent of allof the shapes.
	//	if right aligned then move allthe shapes on the line by the difference
	//		between the width between the margins and the line extent.
	//	if centre aligned then move the shapes half the difference between the
	//		margins and the line extent.
	if( !m_bMeasuring && m_algCurrentPargraph != CHTMLParse::algLeft && m_nFirstShapeOnLine != GetCurrentShapeID() )
	{
		const int nCurrentShape = GetCurrentShapeID() - 1;
		const CSectionABC *psectFirst = m_psect->GetSectionAt( m_nFirstShapeOnLine );
		const CSectionABC *psectSecond = m_psect->GetSectionAt( nCurrentShape );
		const int nExtent =  psectSecond->right -  psectFirst->left;
		const int nDocWidth = GetCurrentWidth();
		const int nSpaceWidth = nDocWidth - nExtent;
		if( m_algCurrentPargraph == CHTMLParse::algCentre )
		{
			// richg - 19990225 - Never shift left!
			nHorizontalDelta = max( 0, nSpaceWidth / 2 );
		}
		else if( m_algCurrentPargraph == CHTMLParse::algRight )
		{
			// richg - 19990225 - Never shift left!
			nHorizontalDelta = max( 0, nSpaceWidth );
		}
	}

	//
	//	Minus one is a signal that the shapes are all the same size.
	m_nNextYPos = m_nYPos;
	const int nCurrentShapeID = GetCurrentShapeID();
	if( m_nFirstShapeOnLine != nCurrentShapeID )
	{
		for( int n = m_nFirstShapeOnLine; n < nCurrentShapeID; n++ )
		{
			CSectionABC *pSect = m_psect->GetSectionAt( n );
			const int nBaseline = GetBaseline( n );
			if( nBaseline >= 0 )
			{
				const int nBaselineDelta = m_nLowestBaseline - nBaseline;
				if( nBaselineDelta || nHorizontalDelta )
				{
					pSect->Offset( nHorizontalDelta, nBaselineDelta );
				}

				//
				//	We only use shapes that have a baseline
				if( pSect->bottom > m_nNextYPos )
				{
					m_nNextYPos = pSect->bottom;
				}
			}

			if( pSect->right > m_nWidth )
				m_nWidth = pSect->right;
		}
	}
}


void CHTMLSectionCreator::AddImage( int nWidth, int nHeight, int nBorder, CImage *pImage, CHTMLParse::Align alg, CHTMLSectionLink* pLink )
{
	ASSERT( pImage );

	CSize size( pImage->GetSize() );
	if( m_dc.IsPrinting() )
		size = m_dc.Scale( size );

	if( nWidth == 0 )
		nWidth = size.cx;
	else
		nWidth = m_dc.ScaleX( nWidth );

	if( nHeight == 0 )
		nHeight = size.cy;
	else
		nHeight = m_dc.ScaleY( nHeight );

	nWidth += m_dc.ScaleX(nBorder * 2);
	nHeight += m_dc.ScaleY(nBorder * 2);

	int nTop = m_nYPos;
	int nBaseline = nHeight;

	if( nWidth > m_nRightMargin - m_nXPos )
	{
		CarriageReturn();
		m_nYPos = m_nNextYPos;
		nTop = m_nYPos;
	}
	int nLeft = m_nXPos;

	switch( alg )
	{
	case CHTMLParse::algBottom:	break;

	case CHTMLParse::algCentre:
	case CHTMLParse::algMiddle:
		nBaseline = nHeight / 2;
		break;

	case CHTMLParse::algTop:
		nBaseline = m_dc.GetCurrentFontBaseline();
		break;

	case CHTMLParse::algLeft:
		{
			nLeft = m_nLeftMargin;
			MarginStackItem msi = { nLeft + nWidth + g_defaults.m_nImageMargin, m_nYPos + nHeight };
			m_stkLeftMargin.Push( msi );
			if( m_nXPos == m_nLeftMargin )
				m_nXPos = msi.nMargin;
			m_nLeftMargin = msi.nMargin;
			
		}
		break;

	case CHTMLParse::algRight:
		{
			nLeft = m_nRightMargin - nWidth - g_defaults.m_nImageMargin;
			MarginStackItem msi = { nLeft, m_nYPos + nHeight };
			m_stkRightMargin.Push( msi );
			m_nRightMargin = msi.nMargin;
		}
		break;
	}
	CHTMLImageSection *pImageSection = new CHTMLImageSection( m_psect, pImage, nBorder );
	pImageSection->Set( nLeft, nTop, nLeft + nWidth, nTop + nHeight );
	if( pLink )
		pImageSection->SetAsLink( pLink );

	if( alg != CHTMLParse::algLeft && alg != CHTMLParse::algRight )
	{
		m_nXPos += nWidth;
		AddBaseline( nBaseline );
	}
}


void CHTMLSectionCreator::AddHorizontalRule( CHTMLParse::Align alg, int nSize, int nWidth, bool bNoShade, COLORREF crColor, CHTMLSectionLink* pLink )
//
//	Horizontal ruler creates a space as tall as it is, also does a carriage return.
{
	const int nDisplayWidth = GetCurrentWidth();
	if( nWidth < 0 )
	{
		// If we are measuring, and looking atthe largest possible size,
		// return some small number, as it is irrelevant!
		if (m_bMeasuring && nDisplayWidth == knFindMaximumWidth)
			nWidth = 1;
		else
			nWidth = int( float( nDisplayWidth ) / 100 * abs(nWidth) );
	}

	int nLeft = m_nLeftMargin;
	if( !m_bMeasuring && nWidth != nDisplayWidth )
	{
		switch( alg )
		{
		case CHTMLParse::algRight:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -