/* IDWriteGdiInterop methods */ virtual HRESULT STDMETHODCALLTYPE CreateFontFromLOGFONT( LOGFONTW const *logFont, IDWriteFont **font) { OutputDebugString("delegate_dwrite_gdi_interop::CreateFontFromLOGFONT"); HRESULT result; UINT32 index; BOOL exists; result = mycoll_->FindFamilyName(logFont->lfFaceName, &index, &exists); if (SUCCEEDED(result)) { result = E_FAIL; if (exists != FALSE) { IDWriteFontFamily *family; result = mycoll_->GetFontFamily(index, &family); if (SUCCEEDED(result)) { result = family->GetFirstMatchingFont( (DWRITE_FONT_WEIGHT)logFont->lfWeight, DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, font); iunknown_release(family); } } } if (FAILED(result)) { OutputDebugString("delegate_dwrite_gdi_interop::CreateFontFromLOGFONT -> fallback"); result = orig_this->CreateFontFromLOGFONT(logFont, font); } return result; }
const float getFontHeightToEmSizeFactor(Font& font, IDWriteFontCollection& dwFontCollection) { // To set the font size factor, we need to get the font metrics BOOL fontFound; uint32 fontIndex; // Search for the font in the font collection using the font name HRESULT hr = dwFontCollection.FindFamilyName (font.getTypefaceName().toWideCharPointer(), &fontIndex, &fontFound); if (! fontFound) fontIndex = 0; IDWriteFontFamily* dwFontFamily = nullptr; hr = dwFontCollection.GetFontFamily (fontIndex, &dwFontFamily); IDWriteFont* dwFont = nullptr; hr = dwFontFamily->GetFirstMatchingFont (DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &dwFont); IDWriteFontFace* dwFontFace = nullptr; hr = dwFont->CreateFontFace (&dwFontFace); // Font metrics are in font design units DWRITE_FONT_METRICS dwFontMetrics; dwFontFace->GetMetrics (&dwFontMetrics); const float totalHeight = std::abs ((float) dwFontMetrics.ascent) + std::abs ((float) dwFontMetrics.descent); const float fontHeightToEmSizeFactor = (float) dwFontMetrics.designUnitsPerEm / totalHeight; safeRelease (&dwFontFace); safeRelease (&dwFont); safeRelease (&dwFontFamily); return fontHeightToEmSizeFactor; }
bool CDirectWriteRenderer::GetFontMetrics(CDirectWriteFont &Font, FontMetrics *pMetrics) { if (pMetrics == nullptr) return false; if (m_pRenderTarget == nullptr) return false; HRESULT hr = E_UNEXPECTED; IDWriteTextFormat *pTextFormat = Font.GetTextFormat(); if (pTextFormat != nullptr) { IDWriteFontCollection *pFontCollection; hr = pTextFormat->GetFontCollection(&pFontCollection); if (SUCCEEDED(hr)) { WCHAR szName[256]; hr = pTextFormat->GetFontFamilyName(szName, lengthof(szName)); if (SUCCEEDED(hr)) { UINT32 Index; BOOL fExists; hr = pFontCollection->FindFamilyName(szName, &Index, &fExists); if (SUCCEEDED(hr)) { IDWriteFontFamily *pFontFamily; hr = pFontCollection->GetFontFamily(Index, &pFontFamily); if (SUCCEEDED(hr)) { IDWriteFont *pFont; hr = pFontFamily->GetFirstMatchingFont( pTextFormat->GetFontWeight(), pTextFormat->GetFontStretch(), pTextFormat->GetFontStyle(), &pFont); if (SUCCEEDED(hr)) { DWRITE_FONT_METRICS Metrics; pFont->GetMetrics(&Metrics); const float Ratio = pTextFormat->GetFontSize() / static_cast<float>(Metrics.designUnitsPerEm); pMetrics->Ascent = Metrics.ascent * Ratio; pMetrics->Descent = Metrics.descent * Ratio; pMetrics->LineGap = Metrics.lineGap * Ratio; pFont->Release(); } pFontFamily->Release(); } } } } pFontCollection->Release(); } return SUCCEEDED(hr); }
bool setupLayout (const AttributedString& text, const float maxWidth, const float maxHeight, ID2D1RenderTarget& renderTarget, IDWriteFactory& directWriteFactory, IDWriteFontCollection& fontCollection, ComSmartPtr<IDWriteTextLayout>& textLayout) { // To add color to text, we need to create a D2D render target // Since we are not actually rendering to a D2D context we create a temporary GDI render target Font defaultFont; BOOL fontFound = false; uint32 fontIndex; fontCollection.FindFamilyName (defaultFont.getTypeface()->getName().toWideCharPointer(), &fontIndex, &fontFound); if (! fontFound) fontIndex = 0; ComSmartPtr<IDWriteFontFamily> dwFontFamily; HRESULT hr = fontCollection.GetFontFamily (fontIndex, dwFontFamily.resetAndGetPointerAddress()); ComSmartPtr<IDWriteFont> dwFont; hr = dwFontFamily->GetFirstMatchingFont (DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, dwFont.resetAndGetPointerAddress()); jassert (dwFont != nullptr); const float defaultFontHeightToEmSizeFactor = getFontHeightToEmSizeFactor (*dwFont); ComSmartPtr<IDWriteTextFormat> dwTextFormat; hr = directWriteFactory.CreateTextFormat (defaultFont.getTypefaceName().toWideCharPointer(), &fontCollection, DWRITE_FONT_WEIGHT_REGULAR, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, defaultFont.getHeight() * defaultFontHeightToEmSizeFactor, L"en-us", dwTextFormat.resetAndGetPointerAddress()); setTextFormatProperties (text, *dwTextFormat); { DWRITE_TRIMMING trimming = { DWRITE_TRIMMING_GRANULARITY_CHARACTER, 0, 0 }; ComSmartPtr<IDWriteInlineObject> trimmingSign; hr = directWriteFactory.CreateEllipsisTrimmingSign (dwTextFormat, trimmingSign.resetAndGetPointerAddress()); hr = dwTextFormat->SetTrimming (&trimming, trimmingSign); } const int textLen = text.getText().length(); hr = directWriteFactory.CreateTextLayout (text.getText().toWideCharPointer(), textLen, dwTextFormat, maxWidth, maxHeight, textLayout.resetAndGetPointerAddress()); if (FAILED (hr) || textLayout == nullptr) return false; const int numAttributes = text.getNumAttributes(); for (int i = 0; i < numAttributes; ++i) addAttributedRange (*text.getAttribute (i), *textLayout, textLen, renderTarget, fontCollection); return true; }
void addAttributedRange (const AttributedString::Attribute& attr, IDWriteTextLayout& textLayout, const int textLen, ID2D1RenderTarget& renderTarget, IDWriteFontCollection& fontCollection) { DWRITE_TEXT_RANGE range; range.startPosition = attr.range.getStart(); range.length = jmin (attr.range.getLength(), textLen - attr.range.getStart()); if (const Font* const font = attr.getFont()) { const String familyName (FontStyleHelpers::getConcreteFamilyName (*font)); BOOL fontFound = false; uint32 fontIndex; fontCollection.FindFamilyName (familyName.toWideCharPointer(), &fontIndex, &fontFound); if (! fontFound) fontIndex = 0; ComSmartPtr<IDWriteFontFamily> fontFamily; HRESULT hr = fontCollection.GetFontFamily (fontIndex, fontFamily.resetAndGetPointerAddress()); ComSmartPtr<IDWriteFont> dwFont; uint32 fontFacesCount = 0; fontFacesCount = fontFamily->GetFontCount(); for (int i = fontFacesCount; --i >= 0;) { hr = fontFamily->GetFont (i, dwFont.resetAndGetPointerAddress()); if (font->getTypefaceStyle() == getFontFaceName (dwFont)) break; } textLayout.SetFontFamilyName (familyName.toWideCharPointer(), range); textLayout.SetFontWeight (dwFont->GetWeight(), range); textLayout.SetFontStretch (dwFont->GetStretch(), range); textLayout.SetFontStyle (dwFont->GetStyle(), range); const float fontHeightToEmSizeFactor = getFontHeightToEmSizeFactor (*dwFont); textLayout.SetFontSize (font->getHeight() * fontHeightToEmSizeFactor, range); } if (const Colour* const colour = attr.getColour()) { ComSmartPtr<ID2D1SolidColorBrush> d2dBrush; renderTarget.CreateSolidColorBrush (D2D1::ColorF (colour->getFloatRed(), colour->getFloatGreen(), colour->getFloatBlue(), colour->getFloatAlpha()), d2dBrush.resetAndGetPointerAddress()); // We need to call SetDrawingEffect with a legimate brush to get DirectWrite to break text based on colours textLayout.SetDrawingEffect (d2dBrush, range); } }
bool IsFamilyInSystemFontCollection(IDWriteFactory* factory, const WCHAR* familyName) { bool result = false; IDWriteFontCollection* systemFontCollection; HRESULT hr = factory->GetSystemFontCollection(&systemFontCollection); if (SUCCEEDED(hr)) { UINT32 familyNameIndex; BOOL familyNameFound; HRESULT hr = systemFontCollection->FindFamilyName( familyName, &familyNameIndex, &familyNameFound); if (SUCCEEDED(hr) && familyNameFound) { result = true; } systemFontCollection->Release(); } return result; }
int main(void) { int argc; LPWSTR *argv; WCHAR *fontname, *string; int len; HDC dc; HFONT font, prevfont; IDWriteFontCollection *sysfc; UINT32 index; BOOL exists; IDWriteFontFamily *dwfamily; IDWriteFont *dwfont; IDWriteFontFace *dwface; featurePreparer *features; HRESULT hr; // TODO would using wmain() be adequate? argv = CommandLineToArgvW(GetCommandLineW(), &argc); if (argv == NULL) dieLE("error getting command-line arguments"); if (argc != 3) { fprintf(stderr, "usage: %ws font string\n", argv[0]); return 1; } fontname = argv[1]; string = argv[2]; len = wcslen(string); // DirectWrite requires COM hr = CoInitialize(NULL); if (hr != S_OK) die("error initializing COM", hr); // Uniscribe requires a device context with the font to use dc = GetDC(NULL); if (dc == NULL) dieLE("error getting screen HDC for Uniscribe"); // TODO DEFAULT_CHARSET might affect the results we get font = CreateFontW(0, 0, 0, 0, 0, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, fontname); if (font == NULL) dieLE("error creating font for Uniscribe"); prevfont = (HFONT) SelectObject(dc, font); if (prevfont == NULL) dieLE("error selecting font into HDC for Uniscribe"); // and initialize DirectWrite hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory), (IUnknown **) (&dwfactory)); if (hr != S_OK) die("error initializing DirectWrite", hr); // and load the font *there* hr = dwfactory->GetSystemFontCollection(&sysfc, TRUE); if (hr != S_OK) die("error loading DirectWrite system font collection", hr); hr = sysfc->FindFamilyName(fontname, &index, &exists); if (hr != S_OK) die("error finding DirectWrite font family", hr); if (!exists) die("font not found in DirectWrite system font collection", E_FAIL); hr = sysfc->GetFontFamily(index, &dwfamily); if (hr != S_OK) die("error loading DirectWrite font family", hr); hr = dwfamily->GetFirstMatchingFont(DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &dwfont); if (hr != S_OK) die("error loading DirectWrite font object", hr); hr = dwfont->CreateFontFace(&dwface); if (hr != S_OK) die("error creating DirectWrite font face", hr); // first, uniscribe only; no features are used // uniscribeTest(dc, string, len, NULL, // doScriptItemize, doScriptShape, "Uniscribe"); // next, unprepared features (NULL values) features = new featurePreparer; //features->add('z','e','r','o',1); //features->add('f','r','a','c',1);features->prepare(len); // uniscribeTest(dc, string, len, features, // doScriptItemizeOpenType, doScriptShapeOpenType, "Uniscribe OpenType"); directwriteAnalyzerTest(dwface, string, len, features); delete features; dwface->Release(); dwfont->Release(); dwfamily->Release(); sysfc->Release(); dwfactory->Release(); SelectObject(dc, prevfont); DeleteObject(font); ReleaseDC(NULL, dc); CoUninitialize(); return 0; }