// 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 "ChooseFont.h" #include "FontEnumeration.h" #include "GdiTextRenderer.h" extern "C" { #include "../resource.h" #include "TypeDefs.h" } //---------------------------------------------------------------------------- IDWriteFactory* g_dwrite = nullptr; static HINSTANCE g_hInstanceNP3; extern "C" void CenterDlgInParent(HWND hDlg); //============================================================================= // // LoadLngString() // static int LoadLngStringW(UINT uID, LPWSTR lpBuffer, int nBufferMax) { const int nLen = LoadStringW(Globals.hLngResContainer, uID, lpBuffer, nBufferMax); return (nLen != 0) ? nLen : LoadStringW(g_hInstanceNP3, uID, lpBuffer, nBufferMax); } /****************************************************************** * * * The ChooseFontDialog class controls all the UI associated with * * the dialog and uses the support routines in FontEnumeration.cpp * * to enumerate fonts and get various information about each one. * * * ******************************************************************/ class ChooseFontDialog { public: explicit ChooseFontDialog(HWND hParent, const WCHAR* localeName, DPI_T dpi, LPCHOOSEFONT lpCFGDI); virtual ~ChooseFontDialog(); ChooseFontDialog() = delete; HRESULT GetTextFormat(IDWriteTextFormat** textFormat); HRESULT GetTextFormat(IDWriteTextFormat* textFormatIn, IDWriteTextFormat** textFormatOut); private: HWND m_parent; HWND m_dialog; WCHAR m_localeName[LOCALE_NAME_MAX_LENGTH]; DPI_T m_currentDPI; LPCHOOSEFONT m_chooseFontStruct; IDWriteFontCollection* m_fontCollection; IDWriteTextFormat* m_currentTextFormat; IDWriteTextFormat* m_renderTextFormat; HRESULT OnFontFamilySelect(); HRESULT OnFontFaceSelect(); HRESULT OnFontSizeSelect(); HRESULT OnFontFamilyNameEdit(HWND hwndFontFamilies); HRESULT OnFontFaceNameEdit(HWND hwndFontFaces); HRESULT OnFontSizeNameEdit(HWND hwndFontSizes); HRESULT DrawSampleText(HDC sampleDC); static INT_PTR CALLBACK CFDialogProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); BOOL OnInitDialog(HWND dialog, HWND hwndFocus, LPARAM lParam); void OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify); void OnDrawItem(HWND hwnd, const DRAWITEMSTRUCT* lpDrawItem); }; /****************************************************************** * * * ChooseFontDialog::ChooseFontDialog * * * * Prepare to display the dialog * * * ******************************************************************/ ChooseFontDialog::ChooseFontDialog(HWND hParent, const WCHAR* localeName, const DPI_T dpi, LPCHOOSEFONT lpCFGDI) : m_parent(hParent) , m_dialog(nullptr) , m_currentDPI(dpi) , m_chooseFontStruct(lpCFGDI) , m_fontCollection(nullptr) , m_currentTextFormat(nullptr) , m_renderTextFormat(nullptr) { if (localeName != nullptr) { StringCchCopy(m_localeName, _ARRAYSIZE(m_localeName), localeName); } else { // Default to the users' locale //GetUserDefaultLocaleName(&m_localeName[0], COUNTOF(m_localeName)); GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME, &m_localeName[0], _ARRAYSIZE(m_localeName)); } } /****************************************************************** * * * ChooseFontDialog::~ChooseFontDialog * * * * Clean up resources * * * ******************************************************************/ ChooseFontDialog::~ChooseFontDialog() { SafeRelease(&m_fontCollection); SafeRelease(&m_currentTextFormat); SafeRelease(&m_renderTextFormat); } /****************************************************************** * * * ChooseFontDialog::ChooseFontDialog * * * * Create and display the dialog initialized to default attributes * * * ******************************************************************/ HRESULT ChooseFontDialog::GetTextFormat(IDWriteTextFormat** textFormat) { HRESULT hr = S_OK; *textFormat = nullptr; // Default to the system font collection SafeRelease(&m_fontCollection); hr = g_dwrite->GetSystemFontCollection(&m_fontCollection); // Create a default text format if (SUCCEEDED(hr)) { SafeRelease(&m_currentTextFormat); const WCHAR* const fontFamilyName = m_chooseFontStruct->lpLogFont->lfFaceName; float const pointSize = static_cast(m_chooseFontStruct->iPointSize) / 10.0f; auto const fontWeight = static_cast(m_chooseFontStruct->lpLogFont->lfWeight); // TODO: mapping? DWRITE_FONT_STYLE const fontStyle = (m_chooseFontStruct->lpLogFont->lfItalic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL); DWRITE_FONT_STRETCH const fontStretch = DWRITE_FONT_STRETCH_NORMAL; hr = g_dwrite->CreateTextFormat( fontFamilyName, m_fontCollection, fontWeight, fontStyle, fontStretch, pointSize, m_localeName, &m_currentTextFormat); } // Open the dialog if (SUCCEEDED(hr)) { if (Globals.hLngResContainer) { hr = static_cast(DialogBoxParam(Globals.hLngResContainer, MAKEINTRESOURCE(IDD_MUI_CHOOSEFONT), m_parent, CFDialogProc, reinterpret_cast(this))); } else { hr = static_cast(DialogBoxParam(g_hInstanceNP3, MAKEINTRESOURCE(IDD_MUI_CHOOSEFONT), m_parent, CFDialogProc, reinterpret_cast(this))); } } // If all went well, and the user didn't cancel, return the new format. if (hr == S_OK) { *textFormat = SafeDetach(&m_currentTextFormat); } return hr; } /****************************************************************** * * * ChooseFontDialog::ChooseFontDialog * * * * Create and display the dialog initialized to attributes in an * * already existing text format. * * * ******************************************************************/ HRESULT ChooseFontDialog::GetTextFormat(IDWriteTextFormat* textFormatIn, IDWriteTextFormat** textFormatOut) { HRESULT hr = S_OK; *textFormatOut = nullptr; SafeSet(&m_currentTextFormat, textFormatIn); // Pull out the input font attributes SafeRelease(&m_fontCollection); hr = m_currentTextFormat->GetFontCollection(&m_fontCollection); if (SUCCEEDED(hr)) { hr = m_currentTextFormat->GetLocaleName(&m_localeName[0], _ARRAYSIZE(m_localeName)); } // Open the dialog if (SUCCEEDED(hr)) { if (Globals.hLngResContainer) { hr = static_cast(DialogBoxParam(Globals.hLngResContainer, MAKEINTRESOURCE(IDD_MUI_CHOOSEFONT), m_parent, CFDialogProc, reinterpret_cast(this))); } else { hr = static_cast(DialogBoxParam(g_hInstanceNP3, MAKEINTRESOURCE(IDD_MUI_CHOOSEFONT), m_parent, CFDialogProc, reinterpret_cast(this))); } } // If all went well, and the user didn't cancel, return the new format. if (hr == S_OK) { *textFormatOut = SafeDetach(&m_currentTextFormat); } return hr; } /****************************************************************** * * * ChooseFontDialog::OnFontFamilySelect * * * * Update the font face list to match the newly select font family * * * ******************************************************************/ HRESULT ChooseFontDialog::OnFontFamilySelect() { HRESULT hr = S_OK; HWND hwndFontFamilyNames = GetDlgItem(m_dialog, IDC_FONT_FAMILY_NAMES); HWND hwndFontFaceNames = GetDlgItem(m_dialog, IDC_FONT_FACE_NAMES); int currentSelection = ComboBox_GetCurSel(hwndFontFamilyNames); // Get the font family name WCHAR fontFamilyName[100]; UINT32 fontFamilyNameLength = ComboBox_GetLBTextLen(hwndFontFamilyNames, currentSelection) + 1; if (fontFamilyNameLength > _ARRAYSIZE(fontFamilyName)) hr = E_NOT_SUFFICIENT_BUFFER; if (SUCCEEDED(hr)) { ComboBox_GetLBText(hwndFontFamilyNames, currentSelection, &fontFamilyName[0]); } // Get the face names for the new font family IDWriteFontFamily* fontFamily = nullptr; std::vector fonts; // Get the font variants for this family if (currentSelection != CB_ERR) hr = GetFonts(m_fontCollection, fontFamilyName, fonts); // Initialize the face name list std::vector fontFaceInfo; if (SUCCEEDED(hr)) { ComboBox_ResetContent(hwndFontFaceNames); GetFontFaceInfo(fonts, m_localeName, fontFaceInfo); } if (SUCCEEDED(hr)) { for (size_t i = 0; i != fontFaceInfo.size(); ++i) { int fontFaceIndex = ComboBox_AddString(hwndFontFaceNames, fontFaceInfo[i].fontFaceName); ComboBox_SetItemData(hwndFontFaceNames, fontFaceIndex, fontFaceInfo[i].PackedFontAttributes()); } } // Select the best fit font face for the current attributes if (SUCCEEDED(hr)) { FontFaceInfo desiredAttributes( L"", m_currentTextFormat->GetFontWeight(), m_currentTextFormat->GetFontStyle(), m_currentTextFormat->GetFontStretch()); int selectedFontFaceName = 0; ULONG bestFitAttributes = GetBestFontAttributes(m_fontCollection, fontFamilyName, desiredAttributes); int fontFaceCount = ComboBox_GetCount(hwndFontFaceNames); for (int i = 0; i != fontFaceCount; ++i) { if (static_cast(ComboBox_GetItemData(hwndFontFaceNames, i)) == bestFitAttributes) { selectedFontFaceName = i; break; } } ComboBox_SetCurSel(hwndFontFaceNames, selectedFontFaceName); OnFontFaceSelect(); } // Release the held font list. for (auto& font : fonts) { SafeRelease(&font); } SafeRelease(&fontFamily); return hr; } /****************************************************************** * * * ChooseFontDialog::OnFontFaceSelect * * * * Record the new font face selection and redraw the sample text. * * * ******************************************************************/ HRESULT ChooseFontDialog::OnFontFaceSelect() { HRESULT hr = S_OK; // Signal the sample text window to redraw itself. InvalidateRect(GetDlgItem(m_dialog, IDC_SAMPLE_BOX), nullptr, false); return hr; } /****************************************************************** * * * ChooseFontDialog::OnFontSizeSelect * * * * Record the new font size and redraw the sample text. * * * ******************************************************************/ HRESULT ChooseFontDialog::OnFontSizeSelect() { HRESULT hr = S_OK; // Signal the sample text window to redraw itself. InvalidateRect(GetDlgItem(m_dialog, IDC_SAMPLE_BOX), nullptr, false); return hr; } /****************************************************************** * * * ChooseFontDialog::OnFontFamilyNameEdit * * * * Watch what is typed into the edit portion of the font family * * combo and automatically select a name if a match is found. As * * an added feature, also match against localized forms of the * * family name. For example the user can type "Meiryo" on a * * Japanese system and it will be found even though it's displayed * * using a localized variant of the name. * * * ******************************************************************/ HRESULT ChooseFontDialog::OnFontFamilyNameEdit(HWND hwndFontFamilies) { HRESULT hr = S_OK; // Save the state of the edit box selection DWORD editSelection = ComboBox_GetEditSel(hwndFontFamilies); int editSelectionBegin = LOWORD(editSelection); int editSelectionEnd = HIWORD(editSelection); // Get the text in the edit portion of the combo WCHAR fontFamilyName[100]; ComboBox_GetText(hwndFontFamilies, &fontFamilyName[0], _ARRAYSIZE(fontFamilyName)); // Try to find an exact match (case-insensitive) int matchingFontFamily = ComboBox_FindStringExact(hwndFontFamilies, -1, fontFamilyName); bool usedAltMatch = false; if (matchingFontFamily == CB_ERR) { // If a match isn't found, scan all for alternate forms in the font // collection. IDWriteFontFamily* fontFamily = nullptr; hr = GetFontFamily(m_fontCollection, fontFamilyName, &fontFamily); if (hr == S_OK) { // If a match is found, get the family name localized to the locale // we're using in the combo box and match against that. usedAltMatch = true; std::wstring localFontFamilyName; hr = GetFontFamilyName(fontFamily, m_localeName, localFontFamilyName); if (SUCCEEDED(hr)) { matchingFontFamily = ComboBox_FindStringExact(hwndFontFamilies, -1, localFontFamilyName.c_str()); } } else if (hr == DWRITE_E_NOFONT) { // Ignore DWRITE_E_NOFONT errors hr = S_OK; } SafeRelease(&fontFamily); } // Process the match, if any if (SUCCEEDED(hr) && matchingFontFamily != CB_ERR) { ComboBox_SetCurSel(hwndFontFamilies, matchingFontFamily); // SetCurSel will update the edit text to match the text of the // selected item. If we matched against an alternate name put that // name back. if (usedAltMatch) ComboBox_SetText(hwndFontFamilies, fontFamilyName); // Reset the edit selection to what is was before SetCurSel. ComboBox_SetEditSel(hwndFontFamilies, editSelectionBegin, editSelectionEnd); hr = OnFontFamilySelect(); } return hr; } /****************************************************************** * * * ChooseFontDialog::OnFontFaceNameEdit * * * * Watch what is typed into the edit portion of the font face * * combo and automatically select a name if a match is found. * * * ******************************************************************/ HRESULT ChooseFontDialog::OnFontFaceNameEdit(HWND hwnd) { HRESULT hr = S_OK; // Save the state of the edit box selection DWORD editSelection = ComboBox_GetEditSel(hwnd); int editSelectionBegin = LOWORD(editSelection); int editSelectionEnd = HIWORD(editSelection); // Try to find the currently typed text WCHAR text[100]; ComboBox_GetText(hwnd, &text[0], _ARRAYSIZE(text)); int selectedItem = ComboBox_FindStringExact(hwnd, -1, text); if (selectedItem != CB_ERR) { // If text is found, select the corresponding list item, put the // selection state back to what it was originally, and redraw the // sample text ComboBox_SetCurSel(hwnd, selectedItem); ComboBox_SetEditSel(hwnd, editSelectionBegin, editSelectionEnd); hr = OnFontFaceSelect(); } return hr; } /****************************************************************** * * * ChooseFontDialog::OnFontSizeNameEdit * * * * Watch what is typed into the edit portion of the font size * * combo and automatically select a name if a match is found. * * * ******************************************************************/ HRESULT ChooseFontDialog::OnFontSizeNameEdit(HWND hwnd) { HRESULT hr = S_OK; // Save the state of the edit box selection DWORD editSelection = ComboBox_GetEditSel(hwnd); int editSelectionBegin = LOWORD(editSelection); int editSelectionEnd = HIWORD(editSelection); // Try to find the currently typed text WCHAR text[100]; ComboBox_GetText(hwnd, &text[0], _ARRAYSIZE(text)); int selectedItem = ComboBox_FindStringExact(hwnd, -1, text); if (selectedItem != CB_ERR) { // If text is found, select the corresponding list item, put the // selection state back to what it was originally, and redraw the // sample text ComboBox_SetCurSel(hwnd, selectedItem); ComboBox_SetEditSel(hwnd, editSelectionBegin, editSelectionEnd); } hr = OnFontSizeSelect(); return hr; } /****************************************************************** * * * ChooseFontDialog::DrawSampleText * * * ******************************************************************/ HRESULT ChooseFontDialog::DrawSampleText(HDC sampleDC) { static WCHAR sampleText[256] = { L'\0' }; if (sampleText[0] == L'\0') { LoadLngStringW(IDS_MUI_EXAMPLE_TEXT, sampleText, _ARRAYSIZE(sampleText)); } HRESULT hr = S_OK; HWND hwndFontFamilies = GetDlgItem(m_dialog, IDC_FONT_FAMILY_NAMES); HWND hwndFontFaces = GetDlgItem(m_dialog, IDC_FONT_FACE_NAMES); HWND hwndFontSizes = GetDlgItem(m_dialog, IDC_FONT_SIZE); HWND hwndSampleBox = GetDlgItem(m_dialog, IDC_SAMPLE_BOX); // Get the currently selected font family. If there isn't one, then just // don't update the text format and continue to use whatever we had before int selectedFontFamily = ComboBox_GetCurSel(hwndFontFamilies); if (selectedFontFamily != CB_ERR) { // Get the font family name WCHAR fontFamilyName[100]; GetWindowText(hwndFontFamilies, &fontFamilyName[0], _ARRAYSIZE(fontFamilyName)); // Get the font face attributes int selectedFontFace = ComboBox_GetCurSel(hwndFontFaces); auto packedAttributes = static_cast(ComboBox_GetItemData(hwndFontFaces, selectedFontFace)); // Get the font size WCHAR fontSizeText[100]; GetWindowText(hwndFontSizes, &fontSizeText[0], _ARRAYSIZE(fontSizeText)); auto pointSize = static_cast(wcstod(fontSizeText, nullptr)); if (pointSize <= 0.0f) { pointSize = 10.0f; } FontFaceInfo fontFaceInfo(fontFamilyName, packedAttributes); // Recreate current text format object SafeRelease(&m_currentTextFormat); hr = g_dwrite->CreateTextFormat( fontFamilyName, m_fontCollection, fontFaceInfo.fontWeight, fontFaceInfo.fontStyle, fontFaceInfo.fontStretch, pointSize, m_localeName, &m_currentTextFormat); // Create the rendering text format object float dipSize = (pointSize * m_currentDPI.y) / 72.0f; SafeRelease(&m_renderTextFormat); hr = g_dwrite->CreateTextFormat( fontFamilyName, m_fontCollection, fontFaceInfo.fontWeight, fontFaceInfo.fontStyle, fontFaceInfo.fontStretch, dipSize, m_localeName, &m_renderTextFormat); } // Get the size of the sample box RECT sampleBounds = {}; GetClientRect(hwndSampleBox, &sampleBounds); UINT width = sampleBounds.right - sampleBounds.left; UINT height = sampleBounds.bottom - sampleBounds.top; // Layout the sample text using the text format and UI bounds (converted to DIPs) IDWriteTextLayout* textLayout = nullptr; if (SUCCEEDED(hr)) { hr = g_dwrite->CreateTextLayout( sampleText, _ARRAYSIZE(sampleText) - 1, m_renderTextFormat, static_cast((width * m_currentDPI.x) / GetDeviceCaps(sampleDC, LOGPIXELSX)), static_cast((height * m_currentDPI.y) / GetDeviceCaps(sampleDC, LOGPIXELSY)), &textLayout); } // Create a DWrite surface to render to GdiTextRenderer* textRenderer = nullptr; if (SUCCEEDED(hr)) { textRenderer = SafeAcquire(new(std::nothrow) GdiTextRenderer()); if (textRenderer != nullptr) hr = textRenderer->Initialize(m_dialog, sampleDC, width, height); else hr = E_FAIL; } if (SUCCEEDED(hr)) { // Fill the DWrite surface with the background color HDC dwriteDC = textRenderer->GetDC(); SetDCBrushColor(dwriteDC, GetSysColor(COLOR_BTNFACE)); FillRect(dwriteDC, &sampleBounds, GetStockBrush(DC_BRUSH)); // Draw the text onto the DWrite surface hr = textLayout->Draw(nullptr, textRenderer, 0, 0); // Copy the DWrite surface to the sample on screen BitBlt( sampleDC, 0, 0, width, height, dwriteDC, 0, 0, SRCCOPY | NOMIRRORBITMAP); } SafeRelease(&textRenderer); SafeRelease(&textLayout); return hr; } /****************************************************************** * * * ChooseFontDialog::WndProc * * * * Dispatch window message to the appropriate hander * * * ******************************************************************/ INT_PTR CALLBACK ChooseFontDialog::CFDialogProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { if (message == WM_INITDIALOG) { SetWindowLongPtr(hWnd, GWLP_USERDATA, lParam); } auto this_ = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); if (this_ != nullptr) { LPCFHOOKPROC hookFct = this_->m_chooseFontStruct->lpfnHook; if (hookFct) { (*hookFct)(hWnd, message, wParam, reinterpret_cast(this_->m_chooseFontStruct)); } switch (message) { HANDLE_MSG(hWnd, WM_INITDIALOG, this_->OnInitDialog); HANDLE_MSG(hWnd, WM_COMMAND, this_->OnCommand); HANDLE_MSG(hWnd, WM_DRAWITEM, this_->OnDrawItem); } } return FALSE; } /****************************************************************** * * * ChooseFontDialog::OnInitDialog * * * * Initialize the dialog by enumerating the font families and * * setting up a hardcoded list of standard font sizes. * * * ******************************************************************/ BOOL ChooseFontDialog::OnInitDialog(HWND dialog, HWND hwndFocus, LPARAM lParam) { m_dialog = dialog; HWND hwndFamilyNames = GetDlgItem(dialog, IDC_FONT_FAMILY_NAMES); HWND hwndSizes = GetDlgItem(dialog, IDC_FONT_SIZE); // Fill in the font family name list. std::vector fontFamilyNames; if (FAILED(GetFontFamilyNames(m_fontCollection, m_localeName, fontFamilyNames))) return FALSE; for (size_t i = 0; i != fontFamilyNames.size(); ++i) ComboBox_AddString(hwndFamilyNames, fontFamilyNames[i].c_str()); // Fill in the hardcoded font sizes static const float FontSizes[] = { 1.5, 2.5, 3.5, 4.5, 5, 5.5, 6, 6.5, 7, 7.5, 8, 8.5, 9, 9.5, 10, 10.5, 11, 11.5, 12, 12.5, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 28, 30, 36, 48, 60, 72, 84, 96 }; WCHAR sizeName[100]; sizeName[0] = '\0'; for (int i = 0; i != _ARRAYSIZE(FontSizes); ++i) { StringCchPrintf(sizeName, _ARRAYSIZE(sizeName), L"%.3G", FontSizes[i]); ComboBox_AddString(hwndSizes, sizeName); } // Select the current size FLOAT fCurFontSize = round(m_currentTextFormat->GetFontSize() * 10.0f) / 10.0f; StringCchPrintf(sizeName, _ARRAYSIZE(sizeName), L"%.3G", fCurFontSize); SetWindowText(hwndSizes, sizeName); if (CB_ERR == ComboBox_SelectString(hwndSizes, -1, sizeName)) SetWindowText(hwndSizes, sizeName); // Select the font family specified in the input text format. int selectedFontFamily = CB_ERR; std::wstring fontFamilyName; if (SUCCEEDED(GetFontFamilyNameFromFormat(m_currentTextFormat, fontFamilyName))) { selectedFontFamily = ComboBox_SelectString(hwndFamilyNames, -1, fontFamilyName.c_str()); } if (selectedFontFamily == CB_ERR) SetWindowText(hwndFamilyNames, fontFamilyName.c_str()); OnFontFamilySelect(); CenterDlgInParent(m_dialog); return TRUE; } /****************************************************************** * * * ChooseFontDialog::OnCommand * * * * Dispatch button clicks, changing listbox selections, etc. * * * ******************************************************************/ void ChooseFontDialog::OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) { if (id == IDCANCEL && codeNotify == BN_CLICKED) EndDialog(hwnd, S_FALSE); else if (id == IDOK && codeNotify == BN_CLICKED) EndDialog(hwnd, S_OK); else if (id == IDC_FONT_FAMILY_NAMES && codeNotify == CBN_SELCHANGE) OnFontFamilySelect(); else if (id == IDC_FONT_FAMILY_NAMES && codeNotify == CBN_EDITCHANGE) OnFontFamilyNameEdit(hwndCtl); else if (id == IDC_FONT_FACE_NAMES && codeNotify == CBN_SELCHANGE) OnFontFaceSelect(); else if (id == IDC_FONT_FACE_NAMES && codeNotify == CBN_EDITCHANGE) OnFontFaceNameEdit(hwndCtl); else if (id == IDC_FONT_SIZE && codeNotify == CBN_SELCHANGE) OnFontSizeSelect(); else if (id == IDC_FONT_SIZE && codeNotify == CBN_EDITCHANGE) OnFontSizeNameEdit(hwndCtl); } /****************************************************************** * * * ChooseFontDialog::OnDrawItem * * * * Redraw the sample text whenever it's window needs updating * * * ******************************************************************/ void ChooseFontDialog::OnDrawItem(HWND hwnd, const DRAWITEMSTRUCT* lpDrawItem) { DrawSampleText(lpDrawItem->hDC); } // ############################################################################ // ############################################################################ static void SetChosenFontFromTextFormat( IDWriteTextFormat* textFormat, LPCHOOSEFONT lpCF, const DPI_T dpi) { if (textFormat != nullptr) { WCHAR fontFamilyName[100]; HDC hdc = GetDC(lpCF->hwndOwner); textFormat->GetFontFamilyName(&fontFamilyName[0], _ARRAYSIZE(fontFamilyName)); float const pointSize = textFormat->GetFontSize(); DWRITE_FONT_WEIGHT const fontWeight = textFormat->GetFontWeight(); DWRITE_FONT_STYLE const fontStyle = textFormat->GetFontStyle(); StringCchCopy(lpCF->lpLogFont->lfFaceName, LF_FACESIZE, fontFamilyName); lpCF->lpLogFont->lfHeight = -MulDiv(static_cast(lround(pointSize)), GetDeviceCaps(lpCF->hDC, LOGPIXELSY), 72); lpCF->iPointSize = static_cast(lround(pointSize * 10.0f)); lpCF->lpLogFont->lfWeight = static_cast(fontWeight); lpCF->lpLogFont->lfItalic = static_cast((((fontStyle == DWRITE_FONT_STYLE_ITALIC) || (fontStyle == DWRITE_FONT_STYLE_OBLIQUE)) ? TRUE : FALSE)); lpCF->lpLogFont->lfQuality = static_cast(CLEARTYPE_QUALITY); ReleaseDC(lpCF->hwndOwner, hdc); } } // ============================================================================ extern "C" bool ChooseFontDirectWrite(HWND hwnd, const WCHAR* localeName, DPI_T dpi, LPCHOOSEFONT lpCFGDI) { if (!lpCFGDI) { return false; } // The Microsoft Security Development Lifecycle recommends that all // applications include the following call to ensure that heap corruptions // do not go unnoticed and therefore do not introduce opportunities // for security exploits. HeapSetInformation(nullptr, HeapEnableTerminationOnCorruption, nullptr, 0); if (dpi.x == 0) { dpi.x = dpi.y = USER_DEFAULT_SCREEN_DPI; } g_hInstanceNP3 = lpCFGDI->hInstance; DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), (IUnknown **)&g_dwrite); IDWriteTextFormat* textFormatOut = nullptr; ChooseFontDialog chooseFont(hwnd, localeName, dpi, lpCFGDI); chooseFont.GetTextFormat(&textFormatOut); SetChosenFontFromTextFormat(textFormatOut, lpCFGDI, dpi); SafeRelease(&textFormatOut); SafeRelease(&g_dwrite); return true; } // ############################################################################