📄 scdcrendtexts_i.cpp
字号:
// Update current position
if (bUpdatingPos)
{
m_PtCurPos.X = (INT)positions[uiCount-1].X;
m_PtCurPos.Y = (INT)positions[uiCount-1].Y;
switch (m_dwTextAlign & (TA_TOP|TA_BASELINE|TA_BOTTOM))
{
case TA_BASELINE:
// do nothing
break;
case TA_TOP:
// We must shift up from base line to top.
m_PtCurPos.Y -= itmAscent;
break;
case TA_BOTTOM:
// We must shift down from base line to bottom.
m_PtCurPos.Y += m_pFont->SCGetDescent();
break;
}
m_PtCurPos.X += (INT)LastChSize.Width;
}
delete [] positions;
// restore transformation
if (bRestoreMat)
m_pGraphics->SetTransform(&svdMatrix);
if (uiOptions & ETO_CLIPPED)
m_pGraphics->SetClip(&ClipRgn);
}
///
/// Add a text to the current path.
///
void CSCEMFdcRenderer::SCAddTextInPath(INT x, INT y, UINT uiOptions, LPCRECT pRect, LPCWSTR pwString,
UINT uiCount, LPCINT pDxWidths, FLOAT fScaleX, FLOAT fScaleY)
{
ASSERT(m_pGraphics);
ASSERT(m_pPath);
ASSERT(m_pFont);
// String's reference point
POINT PtRef;
BOOL bUpdatingPos = (TA_UPDATECP == (m_dwTextAlign & (TA_NOUPDATECP|TA_UPDATECP)));
if (bUpdatingPos)
{
// We must update/use current position.
PtRef.x = m_PtCurPos.X;
PtRef.y = m_PtCurPos.Y;
} else
{
// TA_NOUPDATECP: use the passed-on point
PtRef.x = x;
PtRef.y = y;
}
INT flags = DriverStringOptionsCmapLookup;
if (uiOptions & ETO_GLYPH_INDEX)
{
flags = 0;
// TODO: AddString is unaware of ETO_GLYPH_INDEX
}
// Save last char size and text's vertical extent
RectF LastChSize;
Matrix matrix;
{
PointF PtDummy(0, 0); // cause we don't know if the corresponding parameter can be NULL
Status Res = m_pGraphics->MeasureDriverString((pwString + uiCount - 1), 1, m_pFont,
&PtDummy, flags, &matrix, &LastChSize);
}
// 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 (left,top) glyph positioning
// Glyph's vertical alignment (we can't use StringFormat to do it)
INT iYPos = PtRef.y;
switch (m_dwTextAlign & SC_VTXTALIGN_MASK)
{
case TA_BASELINE:
iYPos -= itmAscent; // AddString uses (left,top) alignment
break;
case TA_TOP:
// Do nothing.
break;
case TA_BOTTOM:
// We must shitf up.
iYPos -= m_pFont->SCGetDescent() + itmAscent;
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;
}
#if 1
// TODO: explain why the text is shifted by (tm.tmInternalLeading + tm.tmExternalLeading)
fXPos -= m_pFont->SCGetInterExternal();
// I know, this is really unacceptable code! Sorry for the inconvenience.
#endif
// 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];
}
GraphicsPath* pPath = (GraphicsPath*)m_pPath;
// if local transformations are required, we will use a sub path to hold them
float fxRatio = (float)(fabs(fScaleY)/fabs(fScaleX));
INT iFontAngle = m_pFont->SCGetAngle();
BOOL bSubPath = ((iFontAngle!=0) || (fScaleX<0) || (fScaleY<0) || (fxRatio!=1));
if (bSubPath)
{
pPath = new GraphicsPath;
}
// Can't use AddString if we don't have FontFamily, emSize, etc... Are you kidding?
// Can't do: pPath->AddString((WCHAR*)pwString, (INT)uiCount, m_pFont, ...);
FontFamily family;
m_pFont->GetFamily(&family);
REAL emSize = m_pFont->GetSize();
INT style = m_pFont->GetStyle();
DWORD dwFontSimul = m_pFont->SCGetSimulStatus();
if (dwFontSimul & SC_FONT_SIMUL_UNDERLINE)
style |= FontStyleUnderline;
if (dwFontSimul & SC_FONT_SIMUL_OVERSTRIKE)
style |= FontStyleStrikeout;
// GDI+1.0 can't position characters in path.
// Good place to say: GDI+ does not work!
// Try doing it one character at a time (but the ETO_GLYPH_INDEX problem still remains)
for (UINT i=0; (i<uiCount); i++)
{
pPath->AddString(pwString+i, 1, &family,
style, emSize, positions[i], NULL);
}
#ifdef SC_SHOW_BBOX
{// Debug stuff
pPath->StartFigure();
pPath->AddLines((const Point*)&BoundingPoly.m_Points, 4);
pPath->CloseFigure();
}
#endif
// Transformations (Documentation in SCDrawText)
if (bSubPath)
{
Matrix pathMat;
// rotate
if (iFontAngle)
{
pathMat.Translate((REAL)PtRef.x, (REAL)PtRef.y);
pathMat.Rotate(-iFontAngle/10.0f);
pathMat.Translate(-(REAL)PtRef.x, -(REAL)PtRef.y);
}
// reflect
if (fScaleY<0)
{// Vertical reflection
XFORM xform;
switch (m_dwTextAlign & SC_VTXTALIGN_MASK)
{
case TA_BASELINE:
BoundingPoly.SCComputeReflectionBase(xform, itmAscent);
break;
case TA_TOP:
BoundingPoly.SCComputeReflectionTop(xform);
break;
case TA_BOTTOM:
BoundingPoly.SCComputeReflectionBottom(xform);
break;
}
Matrix MatReflect(xform.eM11, xform.eM12, xform.eM21, xform.eM22, xform.eDx, xform.eDy);
pathMat.Multiply(&MatReflect);
}
if (fScaleX<0)
{// Horizontal reflection
XFORM xform;
switch (m_dwTextAlign & SC_HTXTALIGN_MASK)
{
case TA_LEFT:
BoundingPoly.SCComputeReflectionLeft(xform);
break;
case TA_CENTER:
// TODO: Reflect about the center
//
break;
case TA_RIGHT:
BoundingPoly.SCComputeReflectionRight(xform);
break;
}
Matrix MatReflect(xform.eM11, xform.eM12, xform.eM21, xform.eM22, xform.eDx, xform.eDy);
pathMat.Multiply(&MatReflect);
}
// scale
if (fxRatio!=1)
{
pathMat.Translate(PtRef.x*(1 - fxRatio), 0);
pathMat.Scale(fxRatio, 1);
}
// clip
// TODO: if ETO_CLIPPED is set, we should clip the path.
// pPath->Intersect(ClipRect);
// transform and add
pPath->Transform(&pathMat);
m_pPath->AddPath(pPath, FALSE);
}
// Update current position? (Don't know what GDI would do)
if (bUpdatingPos)
{
m_PtCurPos.X = (INT)positions[uiCount-1].X;
m_PtCurPos.Y = (INT)positions[uiCount-1].Y;
switch (m_dwTextAlign & (TA_TOP|TA_BASELINE|TA_BOTTOM))
{
case TA_BASELINE:
// do nothing
break;
case TA_TOP:
// We must shift up from base line to top.
m_PtCurPos.Y -= itmAscent;
break;
case TA_BOTTOM:
// We must shift down from base line to bottom.
m_PtCurPos.Y += m_pFont->SCGetDescent();
break;
}
m_PtCurPos.X += (INT)LastChSize.Width;
}
delete [] positions;
}
///
/// Build a non-rotated text box from a reference point text extents
/// This rectangle is ready to use for a (TA_TOP,TA_LEFT) aligned text.
///
void CSCEMFdcRenderer::SCBuildTextRect(ULONG ulTextAlign, POINT PtRef, RECT& ClipRect,
RectF TextSize, INT itmAscent)
{
// Text's horizontal alignment
switch (ulTextAlign & SC_HTXTALIGN_MASK)
{
case TA_LEFT:
ClipRect.left = PtRef.x;
break;
case TA_CENTER:
ClipRect.left = (long)(PtRef.x - TextSize.Width / 2);
break;
case TA_RIGHT:
ClipRect.left = (long)(PtRef.x - TextSize.Width);
break;
}
// Text's vertical alignment
switch (ulTextAlign & SC_VTXTALIGN_MASK)
{
case TA_TOP:
ClipRect.top = PtRef.y;
break;
case TA_BASELINE:
ClipRect.top = PtRef.y - itmAscent;
break;
case TA_BOTTOM:
ClipRect.top = (long)(PtRef.y - TextSize.Height);
break;
}
ClipRect.right = (long)(ClipRect.left + TextSize.Width);
ClipRect.bottom = (long)(ClipRect.top + TextSize.Height);
}
///
/// Compute text witdh
///
INT CSCEMFdcRenderer::SCComputeTextWidth(LPCWSTR pwString, INT iCount, CONST INT* pDxWidths, INT flags)
{
// Compute text's horizontal extent
INT iWdth = 0;
CONST INT* pWdt = pDxWidths;
for (INT i = 0; (i < iCount); i++)
iWdth += *pWdt++;
ASSERT(iWdth>0);
return iWdth;
}
///
/// Construct the parallelogram surrounding a text.
///
void CSCEMFdcRenderer::SCComputeTextBBox(ULONG ulTextAlign, RectF TextSize,
SCRectPolygon& RectPolygon, POINT& PtRef, INT itmAscent)
{
ASSERT(TextSize.Width>0 && TextSize.Height>0);
// make a rectangle for ta_left/ta_top aligned text
RECT rcText;
SCBuildTextRect(ulTextAlign, PtRef, rcText, TextSize, itmAscent);
// transform into polygon
RectPolygon.SCFromRect(&rcText);
#if 0
// rotate if necessary
ASSERT(m_pFont);
INT iFontAngle = m_pFont->SCGetAngle();
if (iFontAngle)
{
// Caution: use this only if reflection is done BEFORE rotation
RectPolygon.SCRotate(iFontAngle, PtRef.x, PtRef.y);
// But if the font angle is already taken into account in another transformation,
// do not rotate the text box.
}
#endif
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -