2025-11-28 00:35:46 +09:00

198 lines
5.7 KiB
C++

// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved
//
//----------------------------------------------------------------------------
#include "Common.h"
#include "RenderTest.h"
#include "TextHelpers.h"
//
// CreateTextFormatFromLOGFONT
//
// Helper function that creates a DWrite text format object from
// the specified LOGFONT.
//
// We use LOGFONT in this application simply because we rely on the
// Win32 font common dialog. If we were implementing our own font
// selection user interface, a more natural approach would be to use
// the DWrite font collection API and not use LOGFONT at all.
//
HRESULT CreateTextFormatFromLOGFONT(
LOGFONT const& logFont,
float fontSize,
OUT IDWriteTextFormat** textFormat
)
{
HRESULT hr = S_OK;
IDWriteGdiInterop* gdiInterop = NULL;
IDWriteFont* font = NULL;
IDWriteFontFamily* fontFamily = NULL;
IDWriteLocalizedStrings* localizedFamilyNames = NULL;
// Conversion to and from LOGFONT uses the IDWriteGdiInterop interface.
if (SUCCEEDED(hr))
{
hr = g_dwriteFactory->GetGdiInterop(&gdiInterop);
}
// Find the font object that best matches the specified LOGFONT.
if (SUCCEEDED(hr))
{
hr = gdiInterop->CreateFontFromLOGFONT(&logFont, &font);
}
// Get the font family to which this font belongs.
if (SUCCEEDED(hr))
{
hr = font->GetFontFamily(&fontFamily);
}
// Get the family names. This returns an object that encapsulates one or
// more names with the same meaning but in different languages.
if (SUCCEEDED(hr))
{
hr = fontFamily->GetFamilyNames(&localizedFamilyNames);
}
// Get the family name at index zero. If we were going to display the name
// we'd want to try to find one that matched the use locale, but for purposes
// of creating a text format object any language will do.
wchar_t familyName[100];
if (SUCCEEDED(hr))
{
hr = localizedFamilyNames->GetString(0, familyName, ARRAYSIZE(familyName));
}
if (SUCCEEDED(hr))
{
// If no font size was passed in use the lfHeight of the LOGFONT.
if (fontSize == 0)
{
// Convert from pixels to DIPs.
fontSize = PixelsToDipsY(logFont.lfHeight);
if (fontSize < 0)
{
// Negative lfHeight represents the size of the em unit.
fontSize = -fontSize;
}
else
{
// Positive lfHeight represents the cell height (ascent + descent).
DWRITE_FONT_METRICS fontMetrics;
font->GetMetrics(&fontMetrics);
// Convert the cell height (ascent + descent) from design units to ems.
float cellHeight = static_cast<float>(fontMetrics.ascent + fontMetrics.descent) /
fontMetrics.designUnitsPerEm;
// Divide the font size by the cell height to get the font em size.
fontSize /= cellHeight;
}
}
}
// The text format includes a locale name. Ideally, this would be the language
// of the text, which may or may not be the same as the primary language of the
// user. However, for our purposes the user locale will do.
wchar_t localeName[LOCALE_NAME_MAX_LENGTH];
if (SUCCEEDED(hr))
{
if (GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH) == 0)
hr = HRESULT_FROM_WIN32(GetLastError());
}
if (SUCCEEDED(hr))
{
// Create the text format object.
hr = g_dwriteFactory->CreateTextFormat(
familyName,
NULL, // no custom font collection
font->GetWeight(),
font->GetStyle(),
font->GetStretch(),
fontSize,
localeName,
textFormat
);
}
SafeRelease(&localizedFamilyNames);
SafeRelease(&fontFamily);
SafeRelease(&font);
SafeRelease(&gdiInterop);
return hr;
}
DWRITE_MATRIX MakeRotateTransform(
float angle, // angle in degrees
float x, // x coordinate of the center of rotation
float y // y coordinate of the center of rotation
)
{
DWRITE_MATRIX matrix;
// Convert degrees to radians.
float radians = (angle * 3.141593f * 2) / 360;
// Initialize the first four members, which comprise a 2x2 matrix.
float sinA = sinf(radians);
float cosA = cosf(radians);
// If the angle is axis aligned, we'll make it a clean matrix.
if (fmod(angle, 90.0f) == 0)
{
sinA = floorf(sinA + .5f);
cosA = floorf(cosA + .5f);
}
matrix.m11 = cosA;
matrix.m12 = sinA;
matrix.m21 = -sinA;
matrix.m22 = cosA;
// Transform the given point.
float xT = (x * matrix.m11) + (y * matrix.m21);
float yT = (x * matrix.m12) + (y * matrix.m22);
// Initialize the displacement to compensate such that the given
// point will be the center of rotation.
matrix.dx = x - xT;
matrix.dy = y - yT;
return matrix;
}
//
// Conversions between pixels and DIPs.
//
float PixelsToDipsX(int x)
{
return x * 96.0f / g_dpiX;
}
float PixelsToDipsY(int y)
{
return y * 96.0f / g_dpiY;
}
int DipsToPixelsX(float x)
{
float pixels = x * g_dpiX * (1/96.0f);
return static_cast<int>(floorf(pixels + 0.5f));
}
int DipsToPixelsY(float y)
{
float pixels = y * g_dpiY * (1/96.0f);
return static_cast<int>(floorf(pixels + 0.5f));
}