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

📄 scdcrendtexts_i.cpp

📁 Source code for EMFexplorer 1.0
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*
*	This file is part of the EMFexplorer projet.
*	Copyright (C) 2004 Smith Charles.
*
*	This library is free software; you can redistribute it and/or
*	modify it under the terms of the GNU Lesser General Public
*	License as published by the Free Software Foundation; either
*	version 2.1 of the License, or (at your option) any later version.
*
*   This library is distributed in the hope that it will be useful,
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
*   Lesser General Public License for more details.
*
*   You should have received a copy of the GNU Lesser General Public
*   License along with this library; if not, write to the Free Software
*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
*
*	Extension: for commercial use, apply the Equity Public License, which
*	adds to the normal terms of the GLPL a condition of donation to the author.
*   If you are interested in support for this source code,
*   contact Smith Charles <smith.charles@free.fr> for more information.
*/


#include "stdafx.h"
#include "SCEMFdcRenderer.h"

using namespace Gdiplus;

///////////////////////////////////////////////////////////////////////////////////////
// Texts management
//
#ifdef _DEBUG
#define SC_SHOW_BBOX
#endif


///
///	Use the current font to draw the given text as GDI ExtTextout.
//  pRect (the clipping and/or opaquing rectangle) is optional,
/// but not pDxWidths (the intercharacter spacing array).
///
/// Note: Computing the rectangle needed by some GDI+ string functions is not a solution.
/// It would result in characters distributed uniformly in that rectangle. For example:
///    [A B C     D E]
/// Would result in something like:
///    [A  B  C  D  E]
///
void CSCEMFdcRenderer::SCDrawText(INT x, INT y, UINT uiOptions, LPCRECT pRect, LPCWSTR pwString,
								UINT uiCount, LPCINT pDxWidths, FLOAT fScaleX, FLOAT fScaleY)
{
	ASSERT(m_pGraphics);
	ASSERT(m_pFont);

	// DrawString isn't powerful enough.
	// It won't let us position the characters acurately, using pDxWidths.
	// And GDI+1.0 Path API is not coherent with Graphics API. We can't do:
	// m_pPath->AddString((WCHAR*)pwString, (INT)uiCount, m_pFont, PtOrg);
	// Good place to say: GDI+ does not work! again!
	// So we must do a lot of work.

	if (m_pPath)
	{
		SCAddTextInPath(x, y, uiOptions, pRect, pwString,
						uiCount, pDxWidths, fScaleX, fScaleY);
		return;
	}

	// String's reference point
	POINT PtRef;
	BOOL bUpdatingPos = (TA_UPDATECP == (m_dwTextAlign & (TA_NOUPDATECP|TA_UPDATECP)));
	if (bUpdatingPos)
	{
		// We must update/use current position.
		// But GDI+1.0 won't track the position for us
		PtRef.x = m_PtCurPos.X;
		PtRef.y = m_PtCurPos.Y;
	} else
	{
		// TA_NOUPDATECP: use the given point
		PtRef.x = x;
		PtRef.y = y;
	}

	INT flags = DriverStringOptionsCmapLookup;
	// "If the DriverStringOptionsCmapLookup flag is set,
	// each value specifies a Unicode character to be displayed.
	// Otherwise, each value specifies an index to a font glyph that defines a
	// character to be displayed."
	if (uiOptions & ETO_GLYPH_INDEX)
		flags = 0;

	// Save last char size and text's vertical extent
	RectF LastChSize;
	Matrix matrix;
	{
		SIZE size;
		BOOL bRes = GetTextExtentPoint32W(m_hDC, (pwString + uiCount - 1), 1, &size);
		ASSERT(bRes);
		LastChSize.Width = (REAL)size.cx;
		LastChSize.Height = (REAL)size.cy;

		//ASSERT(LastChSize.Width>0); // tricky:complex characters can have A+B+C=0
		ASSERT(LastChSize.Height>0);
	}

	// Compute text horizontal extent
	RectF TextSize;
	TextSize.Height = LastChSize.Height;
	TextSize.Width = (REAL)SCComputeTextWidth(pwString, uiCount, pDxWidths, flags);

	SCRectPolygon BoundingPoly;
	INT itmAscent = m_pFont->SCGetAscent();
	SCComputeTextBBox(m_dwTextAlign, TextSize, BoundingPoly, PtRef, itmAscent);

	// Compute placements for baseline glyph positioning
	// Glyph's vertical alignment
	// GDI+1.0 seems to use TA_BASELINE.
	INT iYPos = PtRef.y;
	switch (m_dwTextAlign & SC_VTXTALIGN_MASK)
	{
	case TA_BASELINE:
		// do nothing
		break;

	case TA_TOP:
		// We must shitf down.
		iYPos += itmAscent;
		break;
		
	case TA_BOTTOM:
		// We must shitf up.
		iYPos -= m_pFont->SCGetDescent();
		break;
	}

	// Glyph's horizontal alignment
	REAL fXPos = (REAL)PtRef.x;
	switch (m_dwTextAlign & SC_HTXTALIGN_MASK)
	{
	case TA_LEFT:
		break;
		
	case TA_CENTER:
		fXPos -= TextSize.Width / 2; 
		break;
		
	case TA_RIGHT:
		fXPos -= TextSize.Width;
		break;
	}

	// Compute characters' horizontal placements
	PointF* positions = new PointF[uiCount];
	for (UINT j = 0; (j < uiCount); j++)
	{
		positions[j].X = fXPos;
		positions[j].Y = (REAL)iYPos;
		fXPos += pDxWidths[j];
	}
	
	// Save clipping region
	Region ClipRgn;
	if (uiOptions & ETO_CLIPPED)
		m_pGraphics->GetClip(&ClipRgn);

	Matrix svdMatrix;
	BOOL bRestoreMat = FALSE;
	INT iFontAngle = m_pFont->SCGetAngle();
	if (iFontAngle)
	{// Perform manual font rotation, as GDI+1.0 ignores font escapement
		// (Note that they did not forget to rotate pen objects - yes, rotate pens !!??
		//  But they forgot font objects.)
		// Good place to say: GDI+ does not work!

		// save transform
		bRestoreMat = TRUE;
		m_pGraphics->GetTransform(&svdMatrix);

		// translate to the reference point
		m_pGraphics->TranslateTransform((REAL)PtRef.x, (REAL)PtRef.y);

		// rotate about the reference point
		// (GDI uses positive values for counterclockwise rotation.
		// Prepend negative transformation to obtain counterclockwise rotation)
		m_pGraphics->RotateTransform(-iFontAngle/10.0f);

		// restore original translation
		m_pGraphics->TranslateTransform(-(REAL)PtRef.x, -(REAL)PtRef.y);
	}

	// Special case: We don't know how to use the scaling factors here.
	// But if they contain a reflection, we will reflect the text.
	// Good place to say that our code does not work!
	// 
	// Note also that we are reflecting AFTER rotating (see comments in SCComputeTextBBox)
	// 
	if (fScaleY<0)
	{// Vertical reflection
		// We will reflect about a line passing by the reference point and
		// parallel to the base line

		// Save transform
		if (!bRestoreMat)
		{
			bRestoreMat = TRUE;
			m_pGraphics->GetTransform(&svdMatrix);
		}
		XFORM xform;
		switch (m_dwTextAlign & SC_VTXTALIGN_MASK)
		{
		case TA_BASELINE:
			// Reflect about the base line
			BoundingPoly.SCComputeReflectionBase(xform, itmAscent);
			break;
			
		case TA_TOP:
			// Reflect about the top border
			BoundingPoly.SCComputeReflectionTop(xform);
			break;
			
		case TA_BOTTOM:
			// Reflect about the bottom border
			BoundingPoly.SCComputeReflectionBottom(xform);
			break;
		}

		Matrix MatReflect(xform.eM11, xform.eM12, xform.eM21, xform.eM22, xform.eDx, xform.eDy);
		m_pGraphics->MultiplyTransform(&MatReflect);
	}
	if (fScaleX<0)
	{// Horizontal reflection
		// Save transform
		// We will reflect about a line passing by the reference point and
		// orthogonal with the base line
		if (!bRestoreMat)
		{
			bRestoreMat = TRUE;
			m_pGraphics->GetTransform(&svdMatrix);
		}
								
		XFORM xform;
		switch (m_dwTextAlign & SC_HTXTALIGN_MASK)
		{
		case TA_LEFT:
			// Reflect about the left border
			BoundingPoly.SCComputeReflectionLeft(xform);
			break;
			
		case TA_CENTER:
			// TODO: Reflect about the center
			//
			break;
			
		case TA_RIGHT:
			// Reflect about the right border
			BoundingPoly.SCComputeReflectionRight(xform);
			break;
		}

		Matrix MatReflect(xform.eM11, xform.eM12, xform.eM21, xform.eM22, xform.eDx, xform.eDy);
		m_pGraphics->MultiplyTransform(&MatReflect);
	}
	// also, this is an attempt to condense/inflate text independently of font and DC
	// (again, I have no documentation about this)
	float fxRatio = (float)(fabs(fScaleY)/fabs(fScaleX));
	if (fxRatio!=1)
	{
		if (!bRestoreMat)
		{
			bRestoreMat = TRUE;
			m_pGraphics->GetTransform(&svdMatrix);
		}
		m_pGraphics->TranslateTransform(PtRef.x*(1 - fxRatio), 0);
		m_pGraphics->ScaleTransform(fxRatio, 1);
	}

	// Clipping
	if (uiOptions & ETO_CLIPPED)
	{
		ASSERT(pRect);
		SCIntersectClipRect((RECTL&)*pRect); // TODO: consider setting instead of intersecting
	}

	// Paint background
	if ((uiOptions & ETO_OPAQUE) || OPAQUE==m_dwBkMode)
	{
		// Fill up the background under pRect
		ASSERT(pRect);
		SCRectPolygon ClipPoly;
		if (!IsRectEmpty(pRect))
			ClipPoly.SCFromRect(pRect);
		else
			ClipPoly = BoundingPoly;

		Color BkBrushColor;
		BkBrushColor.SetFromCOLORREF(m_BkColor);
		SolidBrush BkBrush(BkBrushColor);
		m_pGraphics->FillPolygon(&BkBrush, (const Point*)ClipPoly.m_Points, 4);
	}

	// text color
	Color TextBrushColor;
	TextBrushColor.SetFromCOLORREF(m_TextColor);
	SolidBrush TextBrush(TextBrushColor);
	//  -> fails with application-installed fonts selected in DC
	// (that's why we use private font collection)
    m_pGraphics->DrawDriverString(pwString, (INT)uiCount, m_pFont, &TextBrush,
     positions, flags, &matrix);

	// Attributes simulation
	DWORD dwFontSimul = m_pFont->SCGetSimulStatus();
	if (dwFontSimul & (SC_FONT_SIMUL_UNDERLINE|SC_FONT_SIMUL_OVERSTRIKE))
	{
		OUTLINETEXTMETRIC otm;
		GetOutlineTextMetrics(m_hDC, sizeof(otm), &otm);

		PointF PtA = positions[0];
		PointF PtB(PtA.X + TextSize.Width, 0);
		// underline
		if (dwFontSimul & SC_FONT_SIMUL_UNDERLINE)
		{
			Pen AttrPen(TextBrushColor, (REAL)otm.otmsUnderscoreSize); // TODO: review

			PtA.Y = PtA.Y - otm.otmsUnderscorePosition + otm.otmsUnderscoreSize/2; // TODO: review
			PtB.Y = PtA.Y;
			m_pGraphics->DrawLine(&AttrPen, PtA, PtB);
		}
		
		// overstrike
		if (dwFontSimul & SC_FONT_SIMUL_OVERSTRIKE)
		{
			Pen AttrPen(TextBrushColor, (REAL)otm.otmsStrikeoutSize);

			PtA.Y = positions[0].Y - otm.otmsStrikeoutPosition + otm.otmsStrikeoutSize/2;
			PtB.Y = PtA.Y;
			m_pGraphics->DrawLine(&AttrPen, PtA, PtB);
		}
	}

#ifdef SC_SHOW_BBOX
	if (0)
	{// Debug stuff
		Color PenColor;
		PenColor.SetFromCOLORREF(BoundingPoly.m_ColorTopAndRight);
		Pen TRPen(PenColor, 1.0);
		m_pGraphics->DrawLines(&TRPen, (const Point*)&BoundingPoly.m_Points, 3);

		PenColor.SetFromCOLORREF(BoundingPoly.m_ColorBottomAndLeft);
		Pen BLPen(PenColor, 1.0);
		m_pGraphics->DrawLines(&BLPen, (const Point*)&BoundingPoly.m_Points[SCRectPolygon::cnr_RB], 2);
		m_pGraphics->DrawLine(&BLPen, BoundingPoly.m_Points[SCRectPolygon::cnr_LB].x, BoundingPoly.m_Points[SCRectPolygon::cnr_LB].y,
			BoundingPoly.m_Points[SCRectPolygon::cnr_LT].x, BoundingPoly.m_Points[SCRectPolygon::cnr_LT].y);
	}
#endif

⌨️ 快捷键说明

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