Allow the DX rendering engine to run on Windows 7 (#1274)

Certain DirectX features are unavailable on windows 7. The important ones as they are used in the DX renderer are color font rendering and fallback font support. Color fonts did not exist at all on windows 7 so running basic glyphrun rendering should work just fine.

Fallback font support was not exposed to the user in windows 7, making dealing with them difficult. Rather than try to get some workarounds to properly enable it I have opted to just conditionally disable the support on windows 7.
This commit is contained in:
Daniel Griffen 2019-07-11 22:20:15 +00:00 committed by Dustin L. Howett (MSFT)
parent b9cc819afe
commit 0219781753
5 changed files with 53 additions and 33 deletions

View file

@ -7,6 +7,7 @@
#include <wrl.h>
#include <wrl/client.h>
#include <VersionHelpers.h>
using namespace Microsoft::Console::Render;
@ -19,10 +20,10 @@ using namespace Microsoft::Console::Render;
// - font - The DirectWrite font face to use while calculating layout (by default, will fallback if necessary)
// - clusters - From the backing buffer, the text to be displayed clustered by the columns it should consume.
// - width - The count of pixels available per column (the expected pixel width of every column)
CustomTextLayout::CustomTextLayout(IDWriteFactory2* const factory,
CustomTextLayout::CustomTextLayout(IDWriteFactory1* const factory,
IDWriteTextAnalyzer1* const analyzer,
IDWriteTextFormat2* const format,
IDWriteFontFace5* const font,
IDWriteTextFormat* const format,
IDWriteFontFace1* const font,
std::basic_string_view<Cluster> const clusters,
size_t const width) :
_factory{ factory },
@ -134,7 +135,11 @@ CustomTextLayout::CustomTextLayout(IDWriteFactory2* const factory,
RETURN_IF_FAILED(_analyzer->AnalyzeNumberSubstitution(this, 0, textLength, this));
// Perform our custom font fallback analyzer that mimics the pattern of the real analyzers.
RETURN_IF_FAILED(_AnalyzeFontFallback(this, 0, textLength));
// Fallback routines are not available below Windows 8.1, so just skip them and let a replacement character happen.
if (IsWindows8Point1OrGreater())
{
RETURN_IF_FAILED(_AnalyzeFontFallback(this, 0, textLength));
}
// Ensure that a font face is attached to every run
for (auto& run : _runs)

View file

@ -19,10 +19,10 @@ namespace Microsoft::Console::Render
public:
// Based on the Windows 7 SDK sample at https://github.com/pauldotknopf/WindowsSDK7-Samples/tree/master/multimedia/DirectWrite/CustomLayout
CustomTextLayout(IDWriteFactory2* const factory,
CustomTextLayout(IDWriteFactory1* const factory,
IDWriteTextAnalyzer1* const analyzer,
IDWriteTextFormat2* const format,
IDWriteFontFace5* const font,
IDWriteTextFormat* const format,
IDWriteFontFace1* const font,
const std::basic_string_view<::Microsoft::Console::Render::Cluster> clusters,
size_t const width);
@ -90,7 +90,7 @@ namespace Microsoft::Console::Render
UINT8 bidiLevel;
bool isNumberSubstituted;
bool isSideways;
::Microsoft::WRL::ComPtr<IDWriteFontFace5> fontFace;
::Microsoft::WRL::ComPtr<IDWriteFontFace1> fontFace;
FLOAT fontScale;
inline bool ContainsTextPosition(UINT32 desiredTextPosition) const
@ -135,16 +135,16 @@ namespace Microsoft::Console::Render
[[nodiscard]] static UINT32 _EstimateGlyphCount(const UINT32 textLength) noexcept;
private:
const ::Microsoft::WRL::ComPtr<IDWriteFactory2> _factory;
const ::Microsoft::WRL::ComPtr<IDWriteFactory1> _factory;
// DirectWrite analyzer
const ::Microsoft::WRL::ComPtr<IDWriteTextAnalyzer1> _analyzer;
// DirectWrite text format
const ::Microsoft::WRL::ComPtr<IDWriteTextFormat2> _format;
const ::Microsoft::WRL::ComPtr<IDWriteTextFormat> _format;
// DirectWrite font face
const ::Microsoft::WRL::ComPtr<IDWriteFontFace5> _font;
const ::Microsoft::WRL::ComPtr<IDWriteFontFace1> _font;
// The text we're analyzing and processing into a layout
std::wstring _text;

View file

@ -7,6 +7,7 @@
#include <wrl.h>
#include <wrl/client.h>
#include <VersionHelpers.h>
using namespace Microsoft::Console::Render;
@ -239,8 +240,8 @@ void CustomTextRenderer::_FillRectangle(void* clientDrawingContext,
D2D1_POINT_2F baselineOrigin = origin;
baselineOrigin.y += drawingContext->spacing.baseline;
::Microsoft::WRL::ComPtr<ID2D1DeviceContext4> d2dContext4;
RETURN_IF_FAILED(drawingContext->renderTarget->QueryInterface(d2dContext4.GetAddressOf()));
::Microsoft::WRL::ComPtr<ID2D1DeviceContext> d2dContext;
RETURN_IF_FAILED(drawingContext->renderTarget->QueryInterface(d2dContext.GetAddressOf()));
// Draw the background
D2D1_RECT_F rect;
@ -254,13 +255,17 @@ void CustomTextRenderer::_FillRectangle(void* clientDrawingContext,
rect.right += glyphRun->glyphAdvances[i];
}
d2dContext4->FillRectangle(rect, drawingContext->backgroundBrush);
d2dContext->FillRectangle(rect, drawingContext->backgroundBrush);
// Now go onto drawing the text.
// First check if we want a color font and try to extract color emoji first.
if (WI_IsFlagSet(drawingContext->options, D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT))
// Color emoji are only available on Windows 10+
if (WI_IsFlagSet(drawingContext->options, D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT) && IsWindows10OrGreater())
{
::Microsoft::WRL::ComPtr<ID2D1DeviceContext4> d2dContext4;
RETURN_IF_FAILED(d2dContext.As(&d2dContext4));
::Microsoft::WRL::ComPtr<IDWriteFactory4> dwriteFactory4;
RETURN_IF_FAILED(drawingContext->dwriteFactory->QueryInterface(dwriteFactory4.GetAddressOf()));
@ -409,11 +414,11 @@ void CustomTextRenderer::_FillRectangle(void* clientDrawingContext,
_In_ const DWRITE_GLYPH_RUN_DESCRIPTION* glyphRunDescription,
ID2D1Brush* brush)
{
::Microsoft::WRL::ComPtr<ID2D1DeviceContext4> d2dContext4;
RETURN_IF_FAILED(clientDrawingContext->renderTarget->QueryInterface(d2dContext4.GetAddressOf()));
::Microsoft::WRL::ComPtr<ID2D1DeviceContext> d2dContext;
RETURN_IF_FAILED(clientDrawingContext->renderTarget->QueryInterface(d2dContext.GetAddressOf()));
// Using the context is the easiest/default way of drawing.
d2dContext4->DrawGlyphRun(baselineOrigin, glyphRun, glyphRunDescription, brush, measuringMode);
d2dContext->DrawGlyphRun(baselineOrigin, glyphRun, glyphRunDescription, brush, measuringMode);
// However, we could probably add options here and switch out to one of these other drawing methods (making it
// conditional based on the IUnknown* clientDrawingEffect or on some other switches and try these out instead:

View file

@ -10,6 +10,7 @@
#include "../../types/inc/Viewport.hpp"
#include "../../inc/unicode.hpp"
#include "../../inc/DefaultSettings.h"
#include <VersionHelpers.h>
#pragma hdrstop
@ -191,7 +192,16 @@ DxEngine::~DxEngine()
SwapChainDesc.BufferCount = 2;
SwapChainDesc.SampleDesc.Count = 1;
SwapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
SwapChainDesc.Scaling = DXGI_SCALING_NONE;
// DXGI_SCALING_NONE is only valid on Windows 8+
if (IsWindows8OrGreater())
{
SwapChainDesc.Scaling = DXGI_SCALING_NONE;
}
else
{
SwapChainDesc.Scaling = DXGI_SCALING_STRETCH;
}
switch (_chainMode)
{
@ -886,7 +896,7 @@ void DxEngine::_InvalidOr(RECT rc) noexcept
// Get the baseline for this font as that's where we draw from
DWRITE_LINE_SPACING spacing;
RETURN_IF_FAILED(_dwriteTextFormat->GetLineSpacing(&spacing));
RETURN_IF_FAILED(_dwriteTextFormat->GetLineSpacing(&spacing.method, &spacing.height, &spacing.baseline));
// Assemble the drawing context information
DrawingContext context(_d2dRenderTarget.Get(),
@ -1248,9 +1258,9 @@ float DxEngine::GetScaling() const noexcept
FontInfo& pfiFontInfo,
int const iDpi) noexcept
{
Microsoft::WRL::ComPtr<IDWriteTextFormat2> format;
Microsoft::WRL::ComPtr<IDWriteTextFormat> format;
Microsoft::WRL::ComPtr<IDWriteTextAnalyzer1> analyzer;
Microsoft::WRL::ComPtr<IDWriteFontFace5> face;
Microsoft::WRL::ComPtr<IDWriteFontFace1> face;
return _GetProposedFont(pfiFontInfoDesired,
pfiFontInfo,
@ -1352,12 +1362,12 @@ float DxEngine::GetScaling() const noexcept
// - style - Normal, italic, etc.
// Return Value:
// - Smart pointer holding interface reference for queryable font data.
[[nodiscard]] Microsoft::WRL::ComPtr<IDWriteFontFace5> DxEngine::_FindFontFace(const std::wstring& familyName,
[[nodiscard]] Microsoft::WRL::ComPtr<IDWriteFontFace1> DxEngine::_FindFontFace(const std::wstring& familyName,
DWRITE_FONT_WEIGHT weight,
DWRITE_FONT_STRETCH stretch,
DWRITE_FONT_STYLE style) const
{
Microsoft::WRL::ComPtr<IDWriteFontFace5> fontFace;
Microsoft::WRL::ComPtr<IDWriteFontFace1> fontFace;
Microsoft::WRL::ComPtr<IDWriteFontCollection> fontCollection;
THROW_IF_FAILED(_dwriteFactory->GetSystemFontCollection(&fontCollection, false));
@ -1394,9 +1404,9 @@ float DxEngine::GetScaling() const noexcept
[[nodiscard]] HRESULT DxEngine::_GetProposedFont(const FontInfoDesired& desired,
FontInfo& actual,
const int dpi,
Microsoft::WRL::ComPtr<IDWriteTextFormat2>& textFormat,
Microsoft::WRL::ComPtr<IDWriteTextFormat>& textFormat,
Microsoft::WRL::ComPtr<IDWriteTextAnalyzer1>& textAnalyzer,
Microsoft::WRL::ComPtr<IDWriteFontFace5>& fontFace) const noexcept
Microsoft::WRL::ComPtr<IDWriteFontFace1>& fontFace) const noexcept
{
try
{
@ -1508,7 +1518,7 @@ float DxEngine::GetScaling() const noexcept
fontFace = face;
THROW_IF_FAILED(textFormat->SetLineSpacing(&lineSpacing));
THROW_IF_FAILED(textFormat->SetLineSpacing(lineSpacing.method, lineSpacing.height, lineSpacing.baseline));
THROW_IF_FAILED(textFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_NEAR));
THROW_IF_FAILED(textFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP));

View file

@ -146,9 +146,9 @@ namespace Microsoft::Console::Render
// Device-Independent Resources
::Microsoft::WRL::ComPtr<ID2D1Factory> _d2dFactory;
::Microsoft::WRL::ComPtr<IDWriteFactory2> _dwriteFactory;
::Microsoft::WRL::ComPtr<IDWriteTextFormat2> _dwriteTextFormat;
::Microsoft::WRL::ComPtr<IDWriteFontFace5> _dwriteFontFace;
::Microsoft::WRL::ComPtr<IDWriteFactory1> _dwriteFactory;
::Microsoft::WRL::ComPtr<IDWriteTextFormat> _dwriteTextFormat;
::Microsoft::WRL::ComPtr<IDWriteFontFace1> _dwriteFontFace;
::Microsoft::WRL::ComPtr<IDWriteTextAnalyzer1> _dwriteTextAnalyzer;
::Microsoft::WRL::ComPtr<CustomTextRenderer> _customRenderer;
@ -178,7 +178,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT _EnableDisplayAccess(const bool outputEnabled) noexcept;
[[nodiscard]] ::Microsoft::WRL::ComPtr<IDWriteFontFace5> _FindFontFace(const std::wstring& familyName,
[[nodiscard]] ::Microsoft::WRL::ComPtr<IDWriteFontFace1> _FindFontFace(const std::wstring& familyName,
DWRITE_FONT_WEIGHT weight,
DWRITE_FONT_STRETCH stretch,
DWRITE_FONT_STYLE style) const;
@ -186,9 +186,9 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT _GetProposedFont(const FontInfoDesired& desired,
FontInfo& actual,
const int dpi,
::Microsoft::WRL::ComPtr<IDWriteTextFormat2>& textFormat,
::Microsoft::WRL::ComPtr<IDWriteTextFormat>& textFormat,
::Microsoft::WRL::ComPtr<IDWriteTextAnalyzer1>& textAnalyzer,
::Microsoft::WRL::ComPtr<IDWriteFontFace5>& fontFace) const noexcept;
::Microsoft::WRL::ComPtr<IDWriteFontFace1>& fontFace) const noexcept;
[[nodiscard]] COORD _GetFontSize() const noexcept;