Skip to content

Commit

Permalink
Allow the DX rendering engine to run on Windows 7 (#1274)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
ZoeyR authored and DHowett committed Jul 11, 2019
1 parent b9cc819 commit 0219781
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 33 deletions.
13 changes: 9 additions & 4 deletions src/renderer/dx/CustomTextLayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include <wrl.h>
#include <wrl/client.h>
#include <VersionHelpers.h>

using namespace Microsoft::Console::Render;

Expand All @@ -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 },
Expand Down Expand Up @@ -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)
Expand Down
14 changes: 7 additions & 7 deletions src/renderer/dx/CustomTextLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
19 changes: 12 additions & 7 deletions src/renderer/dx/CustomTextRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include <wrl.h>
#include <wrl/client.h>
#include <VersionHelpers.h>

using namespace Microsoft::Console::Render;

Expand Down Expand Up @@ -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;
Expand All @@ -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()));

Expand Down Expand Up @@ -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:
Expand Down
28 changes: 19 additions & 9 deletions src/renderer/dx/DxRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "../../types/inc/Viewport.hpp"
#include "../../inc/unicode.hpp"
#include "../../inc/DefaultSettings.h"
#include <VersionHelpers.h>

#pragma hdrstop

Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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
{
Expand Down Expand Up @@ -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));

Expand Down
12 changes: 6 additions & 6 deletions src/renderer/dx/DxRenderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -178,17 +178,17 @@ 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;

[[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;

Expand Down

0 comments on commit 0219781

Please sign in to comment.