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

📄 htmlsectioncreator.cpp

📁 hl2 source code. Do not use it illegal.
💻 CPP
📖 第 1 页 / 共 2 页
字号:
			nLeft = m_nRightMargin - nWidth;
			break;

		case CHTMLParse::algCentre:
			nLeft = m_nLeftMargin + ( nDisplayWidth - nWidth ) / 2;
			break;
		}
	}

	// Size may need to be scaled, if we are not on a screen
	nSize = m_dc.ScaleY( nSize );

	CHTMLHorizontalRuleSection *psect = new CHTMLHorizontalRuleSection( m_psect, bNoShade, crColor );
	psect->Set( nLeft, m_nYPos, nLeft + nWidth, m_nYPos + nSize );
	if( pLink )
		psect->SetAsLink( pLink );
	
	CarriageReturn();
	m_nYPos = m_nNextYPos;
	m_nYPos += nSize;
}



void CHTMLSectionCreator::AddDocument( CHTMLDocument *pDocument )
{
	//pDocument->Dump();
	m_cCharSet = pDocument->m_cCharSet;

	//	Pointers used to process the anchor information
	CHTMLSectionLink* pLastLink = NULL;
	CHTMLAnchor* pLastAnchor = NULL;
	const UINT uDocumentSize = pDocument->m_arrItems.GetSize();
	for( UINT n = 0; n < uDocumentSize; n++ )
	{
		CHTMLDocumentObject *pItem = pDocument->m_arrItems[ n ];
		switch( pItem->GetType() )
		{
		case CHTMLDocumentObject::knParagraph:
			{
				CHTMLParagraph *pPara = static_cast<CHTMLParagraph *>( pItem );
				if( pPara->IsEmpty() )
					continue;

				NewParagraph( pPara->m_nSpaceAbove, pPara->m_nSpaceBelow, pPara->m_alg );

				const UINT uParagraphSize = pPara->m_arrItems.GetSize();
				for( UINT nItem = 0; nItem < uParagraphSize; nItem++ )
				{
					CHTMLParagraphObject *pParaObj = pPara->m_arrItems[ nItem ];

					// Update the Anchor status
					if (pParaObj->m_pAnchor == NULL || pParaObj->m_pAnchor != pLastAnchor)
						pLastLink = NULL;
		
					switch( pParaObj->GetType() )
					{
					case CHTMLParagraphObject::knText:
						{
							CHTMLTextBlock *pText = static_cast<CHTMLTextBlock *>( pParaObj );
							const HTMLFontDef *pdef = pDocument->GetFontDef( pText->m_uFontDefIndex );
							if( pText->m_bPreformatted )
							{
								AddTextPreformat( pText->m_strText, *pdef, pText->m_crFore , pLastLink );
							}
							else
							{
								AddText( pText->m_strText, *pdef, pText->m_crFore , pLastLink );
							}
						}
						break;

					case CHTMLParagraphObject::knTable:
						AddTable( static_cast<CHTMLTable *>( pParaObj ) );
						break;

					case CHTMLParagraphObject::knList:
						AddList( static_cast<CHTMLList *>( pParaObj ) );
						break;

					case CHTMLParagraphObject::knBlockQuote:
						AddBlockQuote( static_cast<CHTMLBlockQuote *>( pParaObj ) );
						break;


					case CHTMLParagraphObject::knImage:
						{
							CHTMLImage *pImage = static_cast<CHTMLImage *>( pParaObj );
							AddImage( pImage->m_nWidth
									, pImage->m_nHeight
									,	pImage->m_nBorder
									, pImage->m_pImage
									, pImage->m_alg
									, pLastLink
									);
						}
						break;


					case CHTMLParagraphObject::knHorizontalRule:
						{
							CHTMLHorizontalRule *pHR = static_cast<CHTMLHorizontalRule *>( pParaObj );
							AddHorizontalRule( pHR->m_alg
											, pHR->m_nSize
											, pHR->m_nWidth
											, pHR->m_bNoShade
											, pHR->m_crColor
											, pLastLink
											);
						}
						break;

					
					case CHTMLParagraphObject::knAnchor:
						{
							CHTMLAnchor *pAnchor = static_cast<CHTMLAnchor *>( pParaObj );
							// Add an entry to the parent section
							if (pAnchor->m_strLinkTarget.GetLength())
							{
								pLastLink = m_psect->AddLink(pAnchor->m_strLinkTarget, pAnchor->m_strLinkTitle, pAnchor->m_crLink, pAnchor->m_crHover );
								pLastAnchor = pAnchor;
							}
							else
							{
								pLastLink = NULL;
								pLastAnchor = NULL;
							}


							// Handle named section...
							if (pAnchor->m_strLinkName.GetLength())
							{
								m_psect->AddNamedSection(pAnchor->m_strLinkName, CPoint(m_nXPos, m_nYPos));
							}
						}
						break;
					}
				}
			}
			break;
		}
	}
	Finished();
}


void CHTMLSectionCreator::AddTable(CHTMLTable *ptab )
{
	// In order to ensure that the borders and backgrounds will be drawn
	// properly, we will need either sections to display each of those properties
	// and ensure that they are displayed before the cell's contents. This way
	// we do not need another layer of indirection (such as 
	// CHTMLTableSection->CHTMLCellSection->CHTMLTextSection)
	//

	const CSize sizeTable( ptab->GetRowsCols() );
	if( sizeTable.cx && sizeTable.cy )
	{
		if( ptab->m_alg == CHTMLParse::algCentre )
		{
			NewParagraph( 1, 1, m_algCurrentPargraph );
		}

		int nMaxWidth = GetCurrentWidth();

		CHTMLTableLayout layout(ptab, m_dc, m_nDefaultRightMargin - m_nDefaultLeftMargin, m_nZoomLevel );
		int nTableWidth = layout.GetTableWidth();
		
		//
		//	If the table is too wide creep the image/table margins until the table fits or there are no more margins.
		if( nTableWidth  + g_defaults.m_nAlignedTableMargin < nMaxWidth )
		{
			while( m_nDefaultRightMargin != m_nRightMargin && m_nDefaultLeftMargin != m_nRightMargin && nTableWidth + g_defaults.m_nAlignedTableMargin >= GetCurrentWidth() )
			{
				NewParagraph( 1, 1, m_algCurrentPargraph );
			}

			nMaxWidth = GetCurrentWidth();
		}
		
		int m_nKeepYPos = m_nYPos;
		
		//
		//  Note that the default alignment is algTop, which is 
		//  meaningless for tables, but provides the appropriate non-wrapping
		//  behavior
		int nLeftMargin = m_nXPos;
		if( nTableWidth < nMaxWidth )
		{
			switch( ptab->m_alg )
			{
			case CHTMLParse::algRight:
				nLeftMargin = m_nRightMargin - nTableWidth;
				break;

			case CHTMLParse::algCentre:
				nLeftMargin += ( nMaxWidth - nTableWidth ) / 2;
				break;
			}
		}


		// If there is a border or background color, we need a CHTMLTableSection to display them.
		// We could create it without checking, but its wasteful.
		CHTMLTableSection* pTableSection = 0;
		if (ptab->m_nBorder || !ptab->m_bTransparent)
		{
			pTableSection = new CHTMLTableSection( m_psect, ptab->m_nBorder, ptab->m_crBorderDark, ptab->m_crBorderLight, ptab->m_bTransparent, ptab->m_crBgColor);
			// This will need to have it's dimensions set, specifically the botttom!
			pTableSection->Set( nLeftMargin, m_nYPos, nLeftMargin + nTableWidth, m_nYPos );
			// nShapeId = GetCurrentShapeID() - 1;
		}

		ArrayClass<CHTMLTableSection*> arrCellSection( sizeTable.cy );

		//		iterate over the columns again, this time lay them out by calling this function and remember the
		//			tallest cell.
		//		Move onto the next row by bumping up the creator Y position.
		m_nYPos += ptab->m_nBorder;
		const UINT uTableRows = ptab->m_arrRows.GetSize();
		for(UINT nRow = 0; nRow < uTableRows; nRow++ )
		{
			// Skip the border of the table, if there is one.
			m_nXPos = nLeftMargin + m_dc.ScaleX(ptab->m_nBorder);
			m_nYPos += m_dc.ScaleY(ptab->m_nCellSpacing);
			CHTMLTable::CHTMLTableRow *pRow = ptab->m_arrRows[ nRow ];
			int nTallestY = m_nYPos;


			ArrayOfInt arrStartShape;
			ArrayOfInt arrLowest;
			ArrayOfInt arrEndShape;

			const UINT uRowColumns = pRow->m_arrCells.GetSize();
			for( UINT nCol = 0; nCol < uRowColumns; nCol++ )
			{
				// Here we include code to account for borders, spacing, and padding
				const int nOuterLeft = m_nXPos + m_dc.ScaleX(ptab->m_nCellSpacing);
				const int nInnerLeft = nOuterLeft + m_dc.ScaleX(ptab->m_nCellPadding + (ptab->m_nBorder ? 1 : 0));
				const int nInnerRight = nInnerLeft + layout.GetColumnWidth(nCol); 
				const int nOuterRight = nInnerRight + m_dc.ScaleX(ptab->m_nCellPadding + (ptab->m_nBorder ? 1 : 0));
				const int nOuterTop = m_nYPos;
				const int nInnerTop = nOuterTop + m_dc.ScaleY(ptab->m_nCellPadding + (ptab->m_nBorder ? 1 : 0));

				m_nXPos = nOuterRight;
				CHTMLTableCell* pcell = pRow->m_arrCells[nCol];
				// Create a TableSection if there is a border or background color
				if (ptab->m_nBorder || !pcell->m_bTransparent)
				{
					arrCellSection[nCol] = new CHTMLTableSection( m_psect, ptab->m_nBorder ? 1 : 0,  pcell->m_crBorderLight, pcell->m_crBorderDark, pcell->m_bTransparent, pcell->m_crBgColor);
					arrCellSection[nCol]->Set( nOuterLeft, nOuterTop, nOuterRight, nOuterTop);
				}
				else
					arrCellSection[nCol] = NULL;

				arrStartShape.Add( GetCurrentShapeID() );

				CHTMLSectionCreator htCreate( m_psect, m_dc, nInnerTop, nInnerLeft, nInnerRight, m_crBack, false, m_nZoomLevel );
				htCreate.AddDocument( pcell );

				const CSize size( htCreate.GetSize() );
				if( size.cy > nTallestY )
				{	
					nTallestY = size.cy;
				}
				if( pcell->m_nHeight + m_nYPos > nTallestY )
				{	
					nTallestY = pcell->m_nHeight + m_nYPos;
				}
				arrLowest.Add( nTallestY );
				arrEndShape.Add( GetCurrentShapeID() );
			}

			m_nYPos = nTallestY + ptab->m_nCellPadding + (ptab->m_nBorder ? 1 : 0);

			//
			//	Adjust all of the cells to have the same bottom.
			//	Also, moves all of the contained shapes if the vertical alignment dictates
			for (UINT ii = 0; ii < uRowColumns; ++ii)
			{
				if (arrCellSection[ii])
					arrCellSection[ii]->bottom = m_nYPos;

				const CHTMLTableCell* pcell = pRow->m_arrCells[ ii ];
				int nOffset = 0;
				switch( pcell->m_valg )
				{
				case CHTMLParse::algTop:
					//	Leave them as they are
					break;

				case CHTMLParse::algMiddle:
					nOffset = ( nTallestY - arrLowest[ ii ] ) / 2;
					break;

				case CHTMLParse::algBottom:
					nOffset = nTallestY - arrLowest[ ii ];
					break;
				}

				if( nOffset )
				{
					for( int n = arrStartShape[ ii ]; n < arrEndShape[ ii ]; n++ )
					{
						m_psect->GetSectionAt( n )->Offset( 0, nOffset );
					}
				}
			}
			arrStartShape.RemoveAll();
			arrLowest.RemoveAll();
			arrEndShape.RemoveAll();

			m_nYPos++;

			// Good place for a page break, between rows.
			if( m_dc.IsPrinting() && m_nLeftMargin == m_nDefaultLeftMargin && m_nRightMargin == m_nDefaultRightMargin)
			{
				m_psect->AddBreakSection(GetCurrentShapeID());
			}
		}
		// Complete the table section!
		m_nYPos += ptab->m_nCellSpacing;
		if( pTableSection )
		{
			pTableSection->bottom = m_nYPos;
		}

		//	Insert a paragraph if were not floating
		if (ptab->m_alg != CHTMLParse::algLeft && ptab->m_alg != CHTMLParse::algRight)
		{
			if( m_dc.IsPrinting() && m_nLeftMargin == m_nDefaultLeftMargin && m_nRightMargin == m_nDefaultRightMargin )
			{
				m_psect->AddBreakSection(GetCurrentShapeID());
			}
		}
		m_nYPos++;

		if( nTableWidth < nMaxWidth )
		{
			//
			//	For tables that are right or left aligned we need to alter the margin stack.
			//	For 'normal' tables we do nothing.
			switch( ptab->m_alg )
			{
			case CHTMLParse::algRight:
				{
					MarginStackItem msi = { nLeftMargin - g_defaults.m_nAlignedTableMargin, m_nYPos - 1 };
					m_stkRightMargin.Push( msi );
					if( m_nXPos == nLeftMargin )
						m_nXPos = msi.nMargin;
					m_nRightMargin = msi.nMargin;
					m_nYPos = m_nKeepYPos;
				}
				break;

			case CHTMLParse::algLeft:
				{
					MarginStackItem msi = { nLeftMargin + nTableWidth + g_defaults.m_nAlignedTableMargin, m_nYPos - 1 };
					m_stkLeftMargin.Push( msi );
					m_nLeftMargin = msi.nMargin;
					m_nYPos = m_nKeepYPos;
				}
				break;
			}

		}
	}
}

void CHTMLSectionCreator::AddList(CHTMLList *pList )
{
	/*
		A List is similar to a table, in that each list item is a
		document in itself. Lists are laid out by creating the
		bullet, which is right justified along the left margin, 
		and has width knIndentSize. The contents depend on whether
		the list is ordered, and the index of the item.
		The list item contents use the right edge if the bullet space
		as the left margin. That's it! Note that current font properties
		apply to the bullet.
		Only color applies to bullets in unordered lists.
	*/
	static LPCTSTR knBulletText = _T("\xB7");
	static LPCTSTR knBulletFormat = _T("%u.");

	const int nBulletFontSize = GetFontSizeAsPixels( m_dc.GetSafeHdc(), 2, m_nZoomLevel );
	const int nBulletWidth = MulDiv(g_defaults.m_nIndentSize, GetDeviceCaps( m_dc.GetSafeHdc(), LOGPIXELSX), 1000); 
	const int nBulletSpace = MulDiv(g_defaults.m_nIndentSpaceSize, GetDeviceCaps( m_dc.GetSafeHdc(), LOGPIXELSX), 1000); 
	int nIndex = 1;	// Index, used for ordered lists

	// Iterate the list items, creating the bullet and the subdocument.
	const UINT nItems = pList->m_arrItems.GetSize();

	m_nNextYPos += m_dc.GetCurrentFontHeight();

	for (UINT i = 0; i < nItems; ++i)
	{
		int nBulletHeight = 0;
		CHTMLListItem* pItem = pList->m_arrItems[i];

		NewParagraph(0,0,CHTMLParse::algLeft);
		// Do we need to create a bullet?
		if (pItem->m_bBullet)
		{
			// Create the bullet...
			LPCTSTR pcszFont;
			int nFontSize;
			bool bBold, bItalic, bUnderline, bStrikeOut;
			LPCTSTR pcszText = 0;			
			TCHAR szBuffer[12];
			UINT uLength = 1;

			if (pList->m_bOrdered)
			{
				uLength = wsprintf(szBuffer, knBulletFormat, nIndex);
				// Set text parameters
				pcszText = szBuffer;
				pcszFont = pItem->m_strFont;
				nFontSize = GetFontSizeAsPixels( m_dc.GetSafeHdc(), pItem->m_nSize, m_nZoomLevel );
				bBold = pItem->m_bBold;
				bItalic = pItem->m_bItalic;
				bUnderline = pItem->m_bUnderline;
				bStrikeOut = pItem->m_bStrikeout;
			}
			else
			{
				// Set text parameters
				pcszText = knBulletText;
				pcszFont = _T("Symbol");
				nFontSize = nBulletFontSize;
				bBold = false;
				bItalic = false;
				bUnderline = false;
				bStrikeOut = false;
			}

			FontDef fdef( pcszFont, nFontSize, bBold, bItalic, bUnderline, bStrikeOut, m_cCharSet );

			CHTMLTextSection* pText = new CHTMLTextSection( m_psect, pcszText, uLength, fdef, pItem->m_crFore );

			//
			// Position the object...
			m_dc.SelectFont( fdef );

			const int nTextWidth = m_dc.GetTextExtent(pcszText, uLength );
			nBulletHeight = m_nYPos + m_dc.GetCurrentFontHeight();
			const int right = m_nXPos + nBulletWidth;
			const int left = right - nTextWidth;
			pText->Set( left, m_nYPos, right, nBulletHeight );
			// Increment the index
			nIndex++;
		}
		// Now, create the sub-document
		CHTMLSectionCreator htCreate( m_psect, m_dc, m_nYPos, m_nXPos + nBulletWidth + nBulletSpace, m_nRightMargin, m_crBack, false, m_nZoomLevel );
		htCreate.AddDocument( pItem );
		const CSize size( htCreate.GetSize() );
		// Adjust y-pos
		m_nYPos = max(size.cy, nBulletHeight) + 1;
	}
	m_nYPos += m_dc.GetCurrentFontHeight();
}

void CHTMLSectionCreator::AddBlockQuote(CHTMLBlockQuote *pBQ )
{
	/*
		A Blockquote contains a single element, a document. Just lay it out into
		smaller margins.
	*/
	const int nIndentWidth = MulDiv(g_defaults.m_nIndentSize + g_defaults.m_nIndentSpaceSize, GetDeviceCaps( m_dc.GetSafeHdc(), LOGPIXELSX), 1000); 

	NewParagraph(1,1,CHTMLParse::algLeft);
	/* 
		Since there is the possibility that the margins exceed the page width,
		force the quote to be at least as wide as the margins!
	*/
	int nLeft = m_nXPos + nIndentWidth;
	int nRight = m_nRightMargin - nIndentWidth;
	if (nRight < nLeft)
		nRight = nLeft + nIndentWidth;

	CHTMLSectionCreator htCreate( m_psect, m_dc, m_nYPos, nLeft, nRight, m_crBack, false, m_nZoomLevel );
	htCreate.AddDocument( pBQ->m_pDoc );
	const CSize size( htCreate.GetSize() );
	m_nYPos = size.cy + (( m_dc.GetCurrentFontHeight() ) / 2);
	NewParagraph(0, 0, m_algCurrentPargraph);
}

⌨️ 快捷键说明

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