// Loads and initializes application assets when the application is loaded. DWriteOpenTypeEnumerationMain::DWriteOpenTypeEnumerationMain(const std::shared_ptr<DX::DeviceResources>& deviceResources) : m_deviceResources(deviceResources) { // Register to be notified if the device is lost or recreated. m_deviceResources->RegisterDeviceNotify(this); m_sceneRenderer = std::unique_ptr<DWriteOpenTypeEnumerationRenderer>(new DWriteOpenTypeEnumerationRenderer(m_deviceResources)); // Create variables to store the font family and index in the collection Microsoft::WRL::ComPtr<IDWriteFontFamily> tempFontFamily; Microsoft::WRL::ComPtr<IDWriteFont> tempFont; Microsoft::WRL::ComPtr<IDWriteFontFace> tempFontFace; Microsoft::WRL::ComPtr<IDWriteFontCollection> fontCollection; Microsoft::WRL::ComPtr<IDWriteTextAnalyzer> textAnalyzer; UINT32 fontIndex = 0; BOOL isPresent = false; // Get a copy of the system font collection m_deviceResources->GetDWriteFactory()->GetSystemFontCollection(&fontCollection); WCHAR* fontFaceNames[] = {L"Arial", L"Times New Roman", L"Meiryo", L"Gabriola"}; Microsoft::WRL::ComPtr<IDWriteFontFace2>* fontFaces[4] = {&m_arial, &m_times, &m_meiryo, &m_gabriola}; for (int i = 0; i < ARRAYSIZE(fontFaceNames); i++) { fontCollection->FindFamilyName(fontFaceNames[i], &fontIndex, &isPresent); if (isPresent) { DX::ThrowIfFailed( fontCollection->GetFontFamily(fontIndex, &tempFontFamily) ); DX::ThrowIfFailed( tempFontFamily->GetFirstMatchingFont( DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &tempFont ) ); DX::ThrowIfFailed( tempFont->CreateFontFace(&tempFontFace) ); DX::ThrowIfFailed( tempFontFace.As(fontFaces[i]) ); } } // Create the IDWriteTextAnalyzer that we'll need to get OpenType feature coverage from m_deviceResources->GetDWriteFactory()->CreateTextAnalyzer(&textAnalyzer); textAnalyzer.As(&m_textAnalyzer); }
void TextFormatD2D::SetProperties( const WCHAR* fontFamily, int size, bool bold, bool italic, const FontCollection* fontCollection) { auto fontCollectionD2D = (FontCollectionD2D*)fontCollection; Dispose(); WCHAR dwriteFamilyName[LF_FACESIZE]; DWRITE_FONT_WEIGHT dwriteFontWeight = bold ? DWRITE_FONT_WEIGHT_BOLD : DWRITE_FONT_WEIGHT_REGULAR; DWRITE_FONT_STYLE dwriteFontStyle = italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL; DWRITE_FONT_STRETCH dwriteFontStretch = DWRITE_FONT_STRETCH_NORMAL; const float dwriteFontSize = size * (4.0f / 3.0f); // |fontFamily| uses the GDI/GDI+ font naming convention so try to create DirectWrite font // using the GDI family name and then create a text format using the DirectWrite family name // obtained from it. HRESULT hr = Util::GetDWritePropertiesFromGDIProperties( CanvasD2D::c_DWFactory.Get(), fontFamily, bold, italic, dwriteFontWeight, dwriteFontStyle, dwriteFontStretch, dwriteFamilyName, _countof(dwriteFamilyName)); if (SUCCEEDED(hr)) { hr = CanvasD2D::c_DWFactory->CreateTextFormat( dwriteFamilyName, nullptr, dwriteFontWeight, dwriteFontStyle, dwriteFontStretch, dwriteFontSize, L"", &m_TextFormat); } if (FAILED(hr)) { IDWriteFontCollection* dwriteFontCollection = nullptr; // If |fontFamily| is not in the system collection, use the font collection from // |fontCollectionD2D| if possible. if (!Util::IsFamilyInSystemFontCollection(CanvasD2D::c_DWFactory.Get(), fontFamily) && (fontCollectionD2D && fontCollectionD2D->InitializeCollection())) { IDWriteFont* dwriteFont = Util::FindDWriteFontInFontCollectionByGDIFamilyName( fontCollectionD2D->m_Collection, fontFamily); if (dwriteFont) { hr = Util::GetFamilyNameFromDWriteFont( dwriteFont, dwriteFamilyName, _countof(dwriteFamilyName)); if (SUCCEEDED(hr)) { fontFamily = dwriteFamilyName; Util::GetPropertiesFromDWriteFont( dwriteFont, bold, italic, &dwriteFontWeight, &dwriteFontStyle, &dwriteFontStretch); } dwriteFont->Release(); } dwriteFontCollection = fontCollectionD2D->m_Collection; } // Fallback in case above fails. hr = CanvasD2D::c_DWFactory->CreateTextFormat( fontFamily, dwriteFontCollection, dwriteFontWeight, dwriteFontStyle, dwriteFontStretch, dwriteFontSize, L"", &m_TextFormat); } if (SUCCEEDED(hr)) { SetHorizontalAlignment(GetHorizontalAlignment()); SetVerticalAlignment(GetVerticalAlignment()); // Get the family name to in case CreateTextFormat() fallbacked on some other family name. hr = m_TextFormat->GetFontFamilyName(dwriteFamilyName, _countof(dwriteFamilyName)); if (FAILED(hr)) return; Microsoft::WRL::ComPtr<IDWriteFontCollection> collection; Microsoft::WRL::ComPtr<IDWriteFontFamily> fontFamily; UINT32 familyNameIndex; BOOL exists; if (FAILED(m_TextFormat->GetFontCollection(collection.GetAddressOf())) || FAILED(collection->FindFamilyName(dwriteFamilyName, &familyNameIndex, &exists)) || FAILED(collection->GetFontFamily(familyNameIndex, fontFamily.GetAddressOf()))) { return; } Microsoft::WRL::ComPtr<IDWriteFont> font; hr = fontFamily->GetFirstMatchingFont( m_TextFormat->GetFontWeight(), m_TextFormat->GetFontStretch(), m_TextFormat->GetFontStyle(), font.GetAddressOf()); if (FAILED(hr)) return; DWRITE_FONT_METRICS fmetrics; font->GetMetrics(&fmetrics); // GDI+ compatibility: GDI+ adds extra padding below the string when |m_AccurateText| is // |false|. The bottom padding seems to be based on the font metrics so we can calculate it // once and keep using it regardless of the actual string. In some cases, GDI+ also adds // the line gap to the overall height so we will store it as well. const float pixelsPerDesignUnit = dwriteFontSize / (float)fmetrics.designUnitsPerEm; m_ExtraHeight = (((float)fmetrics.designUnitsPerEm / 8.0f) - fmetrics.lineGap) * pixelsPerDesignUnit; m_LineGap = fmetrics.lineGap * pixelsPerDesignUnit; } else { Dispose(); } }