ULONG GetBestFontAttributes(IDWriteFontCollection* fontCollection, const WCHAR* fontFamilyName, const FontFaceInfo& desiredAttributes) { DWRITE_FONT_WEIGHT fontWeight = desiredAttributes.fontWeight; DWRITE_FONT_STYLE fontStyle = desiredAttributes.fontStyle; DWRITE_FONT_STRETCH fontStretch = desiredAttributes.fontStretch; IDWriteFontFamily* fontFamily = NULL; IDWriteFont* font = NULL; if (SUCCEEDED(GetFontFamily(fontCollection, fontFamilyName, &fontFamily))) { if (SUCCEEDED(fontFamily->GetFirstMatchingFont(fontWeight, fontStretch, fontStyle, &font))) { fontWeight = font->GetWeight(); fontStyle = font->GetStyle(); fontStretch = font->GetStretch(); } } SafeRelease(&font); SafeRelease(&fontFamily); FontFaceInfo fontFaceInfo(L"", fontWeight, fontStyle, fontStretch); return fontFaceInfo.PackedFontAttributes(); }
bool TextFormatD2D::GetDWPropertiesFromGDIProperties( const WCHAR* gdiFamilyName, const bool gdiBold, const bool gdiItalic, DWRITE_FONT_WEIGHT& dwFontWeight, DWRITE_FONT_STYLE& dwFontStyle, DWRITE_FONT_STRETCH& dwFontStretch, WCHAR* dwFamilyName, UINT dwFamilyNameSize) { bool result = false; IDWriteFont* dwFont = CreateDWFontFromGDIFamilyName(gdiFamilyName); if (dwFont) { if (GetFamilyNameFromDWFont(dwFont, dwFamilyName, dwFamilyNameSize)) { dwFontWeight = dwFont->GetWeight(); if (gdiBold) { if (dwFontWeight == DWRITE_FONT_WEIGHT_NORMAL) { dwFontWeight = DWRITE_FONT_WEIGHT_BOLD; } else if (dwFontWeight < DWRITE_FONT_WEIGHT_ULTRA_BOLD) { // If 'gdiFamilyName' was e.g. 'Segoe UI Light', |dwFontWeight| wil be equal to // DWRITE_FONT_WEIGHT_LIGHT. If |gdiBold| is true in that case, we need to // increase the weight a little more for similar results with GDI+. // TODO: Is +100 enough? dwFontWeight = (DWRITE_FONT_WEIGHT)(dwFontWeight + 100); } } dwFontStyle = dwFont->GetStyle(); if (gdiItalic && dwFontStyle == DWRITE_FONT_STYLE_NORMAL) { dwFontStyle = DWRITE_FONT_STYLE_ITALIC; } dwFontStretch = dwFont->GetStretch(); result = true; } dwFont->Release(); } return result; }
static void styleChanged(struct fontDialog *f) { LRESULT pos; BOOL selected; IDWriteFont *font; selected = cbGetCurSel(f->styleCombobox, &pos); if (!selected) // on deselect, do nothing return; f->curStyle = pos; font = (IDWriteFont *) cbGetItemData(f->styleCombobox, (WPARAM) (f->curStyle)); // these are for the nearest match when changing the family; see below f->weight = font->GetWeight(); f->style = font->GetStyle(); f->stretch = font->GetStretch(); queueRedrawSampleText(f); }
HRESULT DWriteCreateResources(HDC hdc, wchar_t *text, HFONT hfont) { HRESULT hr = S_OK; // If the DirectWrite factory doesn't exist, create the resources, // only create these resources once. if (!g_pDWriteFactory) { HWND hwnd; RECT r; // DirectWrite variables. IDWriteFontFamily* pFontFamily = NULL; IDWriteFont* pFont = NULL; IDWriteLocalizedStrings* pFamilyNames = NULL; // Logical (GDI) font. LOGFONT lf = {}; UINT32 length = 0; UINT32 index = 0; float fontSize = 0; // length of the string UINT32 textLength = 0; wchar_t *name = NULL; // Get a handle to the DC and the window rect. hwnd = WindowFromDC(hdc); GetClientRect(hwnd, &r); // Calculate the string length. textLength = UINT32(wcslen(text)); // Create the DirectWrite factory. hr = DWriteCreateFactory( DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown**>(&g_pDWriteFactory) ); // Create a GDI interop interface. if (SUCCEEDED(hr)) { hr = g_pDWriteFactory->GetGdiInterop(&g_pGdiInterop); } if (SUCCEEDED(hr)) { // Get a logical font from the font handle. GetObject(hfont, sizeof(LOGFONT), &lf); } // Convert to a DirectWrite font. if (SUCCEEDED(hr)) { hr = g_pGdiInterop->CreateFontFromLOGFONT(&lf, &pFont); } // Get the font family. if (SUCCEEDED(hr)) { hr = pFont->GetFontFamily(&pFontFamily); } // Get a list of localized family names. if (SUCCEEDED(hr)) { hr = pFontFamily->GetFamilyNames(&pFamilyNames); } // Select the first locale. This is OK, because we are not displaying the family name. index = 0; // Get the length of the family name. if (SUCCEEDED(hr)) { hr = pFamilyNames->GetStringLength(index, &length); } if (SUCCEEDED(hr)) { // Allocate a new string. name = new (std::nothrow) wchar_t[length+1]; if (name == NULL) { hr = E_OUTOFMEMORY; } } // Get the actual family name. if (SUCCEEDED(hr)) { hr = pFamilyNames->GetString(index, name, length+1); } if (SUCCEEDED(hr)) { // Calculate the font size. fontSize = (float) -MulDiv(lf.lfHeight, 96, GetDeviceCaps(hdc, LOGPIXELSY)); } // Create a text format using the converted font information. if (SUCCEEDED(hr)) { hr = g_pDWriteFactory->CreateTextFormat( name, // Font family name. NULL, pFont->GetWeight(), pFont->GetStyle(), pFont->GetStretch(), fontSize, L"en-us", &g_pTextFormat ); } // Create a text layout. if (SUCCEEDED(hr)) { hr = g_pDWriteFactory->CreateTextLayout( text, textLength, g_pTextFormat, 1024.0f, 480.0f, &g_pTextLayout ); } // Underline and strikethrough are part of a LOGFONT structure, but are not // part of a DWrite font object so we must set them using the text layout. if(lf.lfUnderline) { DWRITE_TEXT_RANGE textRange = {0, textLength}; g_pTextLayout->SetUnderline(true, textRange); } if(lf.lfStrikeOut) { DWRITE_TEXT_RANGE textRange = {0, textLength}; g_pTextLayout->SetStrikethrough(true, textRange); } // Create a bitmap render target for our custom renderer. if (SUCCEEDED(hr)) { hr = g_pGdiInterop->CreateBitmapRenderTarget(hdc, r.right, r.bottom, &g_pBitmapRenderTarget); } // Create default rendering params for our custom renderer. if (SUCCEEDED(hr)) { hr = g_pDWriteFactory->CreateRenderingParams(&g_pRenderingParams); } if (SUCCEEDED(hr)) { // Initialize the custom renderer class. g_pGdiTextRenderer = new (std::nothrow) GdiTextRenderer(g_pBitmapRenderTarget, g_pRenderingParams); } // Clean up local interfaces. SafeRelease(&pFontFamily); SafeRelease(&pFont); SafeRelease(&pFamilyNames); } return hr; }
HRESULT DWriteContext::SetLOGFONT(const LOGFONTW &logFont, float fontSize) { // Most of this function is copy from: http://msdn.microsoft.com/en-us/library/windows/desktop/dd941783(v=vs.85).aspx HRESULT hr = S_OK; IDWriteFont *font = NULL; IDWriteFontFamily *fontFamily = NULL; IDWriteLocalizedStrings *localizedFamilyNames = NULL; if (SUCCEEDED(hr)) { hr = mGdiInterop->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 = mDWriteFactory->CreateTextFormat( familyName, NULL, // no custom font collection font->GetWeight(), font->GetStyle(), font->GetStretch(), fontSize, localeName, &mTextFormat); } if (SUCCEEDED(hr)) { mFontWeight = static_cast<DWRITE_FONT_WEIGHT>(logFont.lfWeight); mFontStyle = logFont.lfItalic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL; } SafeRelease(&localizedFamilyNames); SafeRelease(&fontFamily); SafeRelease(&font); return hr; }
static void fontDialogDrawSampleText(struct fontDialog *f, ID2D1RenderTarget *rt) { D2D1_COLOR_F color; D2D1_BRUSH_PROPERTIES props; ID2D1SolidColorBrush *black; IDWriteFont *font; IDWriteLocalizedStrings *sampleStrings; BOOL exists; WCHAR *sample; WCHAR *family; IDWriteTextFormat *format; D2D1_RECT_F rect; HRESULT hr; color.r = 0.0; color.g = 0.0; color.b = 0.0; color.a = 1.0; ZeroMemory(&props, sizeof (D2D1_BRUSH_PROPERTIES)); props.opacity = 1.0; // identity matrix props.transform._11 = 1; props.transform._22 = 1; hr = rt->CreateSolidColorBrush( &color, &props, &black); if (hr != S_OK) logHRESULT(L"error creating solid brush", hr); font = (IDWriteFont *) cbGetItemData(f->styleCombobox, (WPARAM) f->curStyle); hr = font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_SAMPLE_TEXT, &sampleStrings, &exists); if (hr != S_OK) exists = FALSE; if (exists) { sample = fontCollectionCorrectString(f->fc, sampleStrings); sampleStrings->Release(); } else sample = L"The quick brown fox jumps over the lazy dog."; // DirectWrite doesn't allow creating a text format from a font; we need to get this ourselves family = cbGetItemText(f->familyCombobox, f->curFamily); hr = dwfactory->CreateTextFormat(family, NULL, font->GetWeight(), font->GetStyle(), font->GetStretch(), // typographic points are 1/72 inch; this parameter is 1/96 inch // fortunately Microsoft does this too, in https://msdn.microsoft.com/en-us/library/windows/desktop/dd371554%28v=vs.85%29.aspx f->curSize * (96.0 / 72.0), // see http://stackoverflow.com/questions/28397971/idwritefactorycreatetextformat-failing and https://msdn.microsoft.com/en-us/library/windows/desktop/dd368203.aspx // TODO use the current locale again? L"", &format); if (hr != S_OK) logHRESULT(L"error creating IDWriteTextFormat", hr); uiFree(family); rect.left = 0; rect.top = 0; rect.right = realGetSize(rt).width; rect.bottom = realGetSize(rt).height; rt->DrawText(sample, wcslen(sample), format, &rect, black, // TODO really? D2D1_DRAW_TEXT_OPTIONS_NONE, DWRITE_MEASURING_MODE_NATURAL); format->Release(); if (exists) uiFree(sample); black->Release(); }