You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
387 lines
11 KiB
387 lines
11 KiB
//// DspDraws.CPP - Display plaintext using DrawString API
|
|
//
|
|
//
|
|
|
|
|
|
#include "precomp.hxx"
|
|
#include "global.h"
|
|
#include "gdiplus.h"
|
|
|
|
|
|
|
|
/*
|
|
REAL GetEmHeightInPoints(
|
|
const Font *font,
|
|
const Graphics *graphics
|
|
)
|
|
{
|
|
FontFamily family;
|
|
font->GetFamily(&family);
|
|
|
|
INT style = font->GetStyle();
|
|
|
|
REAL pixelsPerPoint = REAL(graphics->GetDpiY() / 72.0);
|
|
|
|
REAL lineSpacingInPixels = font->GetHeight(graphics);
|
|
|
|
REAL emHeightInPixels = lineSpacingInPixels * family.GetEmHeight(style)
|
|
/ family.GetLineSpacing(style);
|
|
|
|
REAL emHeightInPoints = emHeightInPixels / pixelsPerPoint;
|
|
|
|
return emHeightInPoints;
|
|
}
|
|
*/
|
|
|
|
|
|
|
|
|
|
void PaintDrawString(
|
|
HDC hdc,
|
|
int *piY,
|
|
RECT *prc,
|
|
int iLineHeight) {
|
|
|
|
int icpLineStart; // First character of line
|
|
int icpLineEnd; // End of line (end of buffer or index of CR character)
|
|
|
|
|
|
|
|
// Establish available width and height in device coordinates
|
|
|
|
int plainTextWidth = prc->right - prc->left;
|
|
int plainTextHeight = prc->bottom - *piY;
|
|
|
|
|
|
// Draw a simple figure in the world coordinate system
|
|
|
|
Graphics *g = NULL;
|
|
|
|
Metafile *metafile = NULL;
|
|
|
|
if (g_testMetafile)
|
|
{
|
|
metafile = new Metafile(L"c:\\texttest.emf", hdc);
|
|
g = new Graphics(metafile);
|
|
}
|
|
else
|
|
{
|
|
g = new Graphics(hdc);
|
|
}
|
|
|
|
|
|
Matrix matrix;
|
|
|
|
|
|
g->ResetTransform();
|
|
g->SetPageUnit(UnitPixel);
|
|
g->TranslateTransform(REAL(prc->left), REAL(*piY));
|
|
|
|
g->SetSmoothingMode(g_SmoothingMode);
|
|
|
|
g->SetTextContrast(g_GammaValue);
|
|
g->SetTextRenderingHint(g_TextMode);
|
|
|
|
SolidBrush whiteBrush(Color(0xff, 0xff, 0xff));
|
|
|
|
Color grayColor(0xc0, 0xc0, 0xc0);
|
|
SolidBrush grayBrush(grayColor);
|
|
Pen grayPen(&grayBrush, 1.0);
|
|
|
|
Color blackColor(0, 0, 0);
|
|
SolidBrush blackBrush(blackColor);
|
|
Pen blackPen(&blackBrush, 1.0);
|
|
|
|
|
|
|
|
// Clear the background
|
|
|
|
RectF rEntire(0, 0, REAL(plainTextWidth), REAL(plainTextHeight));
|
|
g->FillRectangle(g_textBackBrush, rEntire);
|
|
|
|
|
|
// Apply selected world transform, adjusted to middle of the plain text
|
|
// area.
|
|
|
|
g->SetTransform(&g_WorldTransform);
|
|
g->TranslateTransform(
|
|
REAL(prc->left + plainTextWidth/2),
|
|
REAL(*piY + plainTextHeight/2),
|
|
MatrixOrderAppend);
|
|
|
|
|
|
Font font(
|
|
&FontFamily(g_style[0].faceName),
|
|
REAL(g_style[0].emSize),
|
|
g_style[0].style,
|
|
g_fontUnit
|
|
);
|
|
|
|
|
|
|
|
|
|
// Put some text in the middle
|
|
|
|
RectF textRect(REAL(-25*plainTextWidth/100), REAL(-25*plainTextHeight/100),
|
|
REAL( 50*plainTextWidth/100), REAL( 50*plainTextHeight/100));
|
|
|
|
|
|
StringFormat format(g_typographic ? StringFormat::GenericTypographic() : StringFormat::GenericDefault());
|
|
format.SetFormatFlags(g_formatFlags);
|
|
format.SetTrimming(g_lineTrim);
|
|
format.SetAlignment(g_align);
|
|
format.SetLineAlignment(g_lineAlign);
|
|
format.SetHotkeyPrefix(g_hotkey);
|
|
|
|
format.SetDigitSubstitution(g_Language, g_DigitSubstituteMode);
|
|
|
|
REAL tab[3] = {textRect.Width/4,
|
|
textRect.Width*3/16,
|
|
textRect.Width*1/8};
|
|
|
|
format.SetTabStops(0.0, sizeof(tab)/sizeof(REAL), tab);
|
|
|
|
|
|
if (!g_AutoDrive)
|
|
{
|
|
// Display selection region if any
|
|
|
|
if (g_iFrom || g_iTo)
|
|
{
|
|
if (g_RangeCount > 0)
|
|
{
|
|
Region regions[MAX_RANGE_COUNT];
|
|
|
|
format.SetMeasurableCharacterRanges(g_RangeCount, g_Ranges);
|
|
Status status = g->MeasureCharacterRanges(g_wcBuf, g_iTextLen, &font, textRect, &format, g_RangeCount, regions);
|
|
|
|
if (status == Ok)
|
|
{
|
|
Pen lightGrayPen(&SolidBrush(Color(0x80,0x80,0x80)), 1.0);
|
|
INT rangeCount = g_RangeCount;
|
|
Matrix identity;
|
|
|
|
while (rangeCount > 0)
|
|
{
|
|
/*INT scanCount = regions[rangeCount - 1].GetRegionScansCount(&identity);
|
|
RectF *boxes = new RectF[scanCount];
|
|
|
|
regions[rangeCount - 1].GetRegionScans(&identity, boxes, &scanCount);
|
|
|
|
for (INT i = 0; i < scanCount; i++)
|
|
{
|
|
g->DrawRectangle(&lightGrayPen, boxes[i]);
|
|
}
|
|
|
|
delete [] boxes;
|
|
|
|
rangeCount--;
|
|
*/
|
|
g->FillRegion(&SolidBrush(Color(0xc0,0xc0,0xc0)), ®ions[--rangeCount]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!g_AutoDrive)
|
|
{
|
|
// Outline the layout rectangle
|
|
|
|
g->DrawRectangle(&grayPen, textRect);
|
|
|
|
// Measure and outline the text
|
|
|
|
RectF boundingBox;
|
|
INT codepointsFitted;
|
|
INT linesFilled;
|
|
|
|
g->MeasureString(
|
|
g_wcBuf, g_iTextLen, &font, textRect, &format, // In
|
|
&boundingBox, &codepointsFitted, &linesFilled); // Out
|
|
|
|
Pen lightGrayPen(&SolidBrush(Color(0x80,0x80,0x80)), 1.0);
|
|
|
|
g->DrawRectangle(&lightGrayPen, boundingBox);
|
|
|
|
// Also draw horizontal and vertical lines away from the rectangle
|
|
// corners - this is to check that line and rectangle drawing coordinates
|
|
// work consistently in a negative x scale (they didn't in GDI: the
|
|
// rectangle and lines differed by one pixel).
|
|
|
|
g->DrawLine(
|
|
&lightGrayPen,
|
|
boundingBox.X, boundingBox.Y,
|
|
boundingBox.X-plainTextWidth/20, boundingBox.Y);
|
|
g->DrawLine(
|
|
&lightGrayPen,
|
|
boundingBox.X, boundingBox.Y,
|
|
boundingBox.X, boundingBox.Y-plainTextHeight/20);
|
|
|
|
g->DrawLine(
|
|
&lightGrayPen,
|
|
boundingBox.X+boundingBox.Width, boundingBox.Y,
|
|
boundingBox.X+boundingBox.Width+plainTextWidth/20, boundingBox.Y);
|
|
g->DrawLine(
|
|
&lightGrayPen,
|
|
boundingBox.X+boundingBox.Width, boundingBox.Y,
|
|
boundingBox.X+boundingBox.Width, boundingBox.Y-plainTextHeight/20);
|
|
|
|
|
|
g->DrawLine(
|
|
&lightGrayPen,
|
|
boundingBox.X, boundingBox.Y+boundingBox.Height,
|
|
boundingBox.X-plainTextWidth/20, boundingBox.Y+boundingBox.Height);
|
|
g->DrawLine(
|
|
&lightGrayPen,
|
|
boundingBox.X, boundingBox.Y+boundingBox.Height,
|
|
boundingBox.X, boundingBox.Y+boundingBox.Height+plainTextHeight/20);
|
|
|
|
g->DrawLine(
|
|
&lightGrayPen,
|
|
boundingBox.X+boundingBox.Width, boundingBox.Y+boundingBox.Height,
|
|
boundingBox.X+boundingBox.Width+plainTextWidth/20, boundingBox.Y+boundingBox.Height);
|
|
g->DrawLine(
|
|
&lightGrayPen,
|
|
boundingBox.X+boundingBox.Width, boundingBox.Y+boundingBox.Height,
|
|
boundingBox.X+boundingBox.Width, boundingBox.Y+boundingBox.Height+plainTextHeight/20);
|
|
|
|
|
|
|
|
WCHAR metricString[100];
|
|
wsprintfW(metricString, L"Codepoints fitted %d\r\nLines filled %d\r\nRanges %d.", codepointsFitted, linesFilled, g_RangeCount);
|
|
|
|
REAL x, y;
|
|
if (g_formatFlags & StringFormatFlagsDirectionVertical)
|
|
{
|
|
if (g_formatFlags & StringFormatFlagsDirectionRightToLeft)
|
|
{
|
|
x = textRect.X;
|
|
y = textRect.Y + textRect.Height/2;
|
|
}
|
|
else
|
|
{
|
|
x = textRect.X + textRect.Width;
|
|
y = textRect.Y + textRect.Height/2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
x = textRect.X + textRect.Width/2;
|
|
y = textRect.Y + textRect.Height;
|
|
}
|
|
|
|
g->DrawString(
|
|
metricString,-1,
|
|
&Font(&FontFamily(L"Tahoma"), 12, NULL, UnitPoint),
|
|
PointF(x, y),
|
|
&format,
|
|
&SolidBrush(Color(0x80,0x80,0x80))
|
|
);
|
|
|
|
g->MeasureString(
|
|
metricString,-1,
|
|
&Font(&FontFamily(L"Tahoma"), 12, NULL, UnitPoint),
|
|
PointF(x, y),
|
|
&format,
|
|
&boundingBox
|
|
);
|
|
|
|
g->DrawRectangle(&lightGrayPen, boundingBox);
|
|
}
|
|
|
|
|
|
// Actually draw the text string. We do this last so it appears on top of
|
|
// the construction and measurement lines we have just drawn.
|
|
|
|
for(int iRender=0;iRender<g_iNumRenders;iRender++)
|
|
{
|
|
g->DrawString(g_wcBuf, g_iTextLen, &font, textRect, &format, g_textBrush);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
// Test Font from Logfont, and generic layout
|
|
|
|
HDC derivedDc = g->GetHDC();
|
|
|
|
HFONT hFont = CreateFontW(
|
|
iLineHeight/2, // height of font
|
|
0, // average character width
|
|
0, // angle of escapement
|
|
0, // base-line orientation angle
|
|
0, // font weight
|
|
0, // italic attribute option
|
|
1, // underline attribute option
|
|
0, // strikeout attribute option
|
|
1, // character set identifier
|
|
0, // output precision
|
|
0, // clipping precision
|
|
0, // output quality
|
|
0, // pitch and family
|
|
g_style[0].faceName // typeface name
|
|
);
|
|
|
|
HFONT hOldFont = (HFONT) SelectObject(hdc, hFont);
|
|
Font fontFromDc(hdc);
|
|
ExtTextOutW(hdc, prc->left, prc->bottom-iLineHeight, 0, NULL, L"By ExtTextOut - AaBbCcDdEeFfGgQq", 32, NULL);
|
|
DeleteObject(SelectObject(hdc, hOldFont));
|
|
g->ReleaseHDC(derivedDc);
|
|
|
|
REAL emHeightInPoints = GetEmHeightInPoints(&fontFromDc, &g);
|
|
|
|
|
|
// Test the easy layout string format
|
|
|
|
g->DrawString(
|
|
L"AaBbCcDdEeFfGgQq - DrawString default layout", -1,
|
|
&fontFromDc, // Font(*FontFamily::GenericMonospace(), 18.0, 0, UnitPoint),
|
|
PointF(0.0, REAL(plainTextHeight/2 - iLineHeight)),
|
|
StringFormat::GenericDefault(),
|
|
&blackBrush
|
|
);
|
|
|
|
|
|
// Test typographic string format
|
|
|
|
g->DrawString(
|
|
L"Typographic layout", -1,
|
|
&Font(FontFamily::GenericSansSerif(), 10),
|
|
PointF(0.0, REAL(plainTextHeight/2 - 2*iLineHeight)),
|
|
StringFormat::GenericTypographic(),
|
|
&blackBrush
|
|
);
|
|
*/
|
|
|
|
|
|
delete g;
|
|
|
|
if (metafile)
|
|
{
|
|
delete metafile;
|
|
}
|
|
|
|
if (g_testMetafile)
|
|
{
|
|
// Playback metafile to screen
|
|
Metafile emfplus(L"c:\\texttest.emf");
|
|
Graphics graphPlayback(hdc);
|
|
graphPlayback.ResetTransform();
|
|
graphPlayback.TranslateTransform(REAL(prc->left), REAL(*piY));
|
|
graphPlayback.DrawImage(
|
|
&emfplus,
|
|
REAL(0),
|
|
REAL(0),
|
|
REAL(plainTextWidth),
|
|
REAL(plainTextHeight)
|
|
);
|
|
graphPlayback.Flush();
|
|
}
|
|
|
|
*piY += plainTextHeight;
|
|
}
|
|
|
|
|