2019-05-03 00:29:04 +02:00
|
|
|
// Copyright (c) Microsoft Corporation.
|
|
|
|
// Licensed under the MIT license.
|
|
|
|
|
|
|
|
#include "precomp.h"
|
|
|
|
|
|
|
|
#include "WddmConRenderer.hpp"
|
|
|
|
|
|
|
|
#include "main.h"
|
|
|
|
|
|
|
|
#pragma hdrstop
|
|
|
|
|
|
|
|
//
|
|
|
|
// Default non-bright white.
|
|
|
|
//
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
#define DEFAULT_COLOR_ATTRIBUTE (0xC)
|
2019-05-03 00:29:04 +02:00
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
#define DEFAULT_FONT_WIDTH (8)
|
|
|
|
#define DEFAULT_FONT_HEIGHT (12)
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
using namespace Microsoft::Console::Render;
|
|
|
|
|
|
|
|
WddmConEngine::WddmConEngine() :
|
|
|
|
RenderEngineBase(),
|
|
|
|
_hWddmConCtx(INVALID_HANDLE_VALUE),
|
|
|
|
_displayHeight(0),
|
|
|
|
_displayWidth(0),
|
|
|
|
_displayState(nullptr),
|
|
|
|
_currentLegacyColorAttribute(DEFAULT_COLOR_ATTRIBUTE)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void WddmConEngine::FreeResources(ULONG displayHeight)
|
|
|
|
{
|
|
|
|
if (_displayState)
|
|
|
|
{
|
|
|
|
for (ULONG i = 0; i < displayHeight; i++)
|
|
|
|
{
|
|
|
|
if (_displayState[i])
|
|
|
|
{
|
|
|
|
if (_displayState[i]->Old)
|
|
|
|
{
|
|
|
|
free(_displayState[i]->Old);
|
|
|
|
}
|
|
|
|
if (_displayState[i]->New)
|
|
|
|
{
|
|
|
|
free(_displayState[i]->New);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(_displayState[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(_displayState);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_hWddmConCtx != INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
WDDMConDestroy(_hWddmConCtx);
|
|
|
|
_hWddmConCtx = INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
WddmConEngine::~WddmConEngine()
|
|
|
|
{
|
|
|
|
FreeResources(_displayHeight);
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::Initialize() noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
RECT DisplaySize;
|
|
|
|
CD_IO_DISPLAY_SIZE DisplaySizeIoctl;
|
|
|
|
|
|
|
|
if (_hWddmConCtx == INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
hr = WDDMConCreate(&_hWddmConCtx);
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
{
|
|
|
|
hr = WDDMConGetDisplaySize(_hWddmConCtx, &DisplaySizeIoctl);
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
{
|
|
|
|
DisplaySize.top = 0;
|
|
|
|
DisplaySize.left = 0;
|
|
|
|
DisplaySize.bottom = (LONG)DisplaySizeIoctl.Height;
|
|
|
|
DisplaySize.right = (LONG)DisplaySizeIoctl.Width;
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
_displayState = (PCD_IO_ROW_INFORMATION*)calloc(DisplaySize.bottom, sizeof(PCD_IO_ROW_INFORMATION));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
if (_displayState != nullptr)
|
|
|
|
{
|
|
|
|
for (LONG i = 0; i < DisplaySize.bottom; i++)
|
|
|
|
{
|
|
|
|
_displayState[i] = (PCD_IO_ROW_INFORMATION)calloc(1, sizeof(CD_IO_ROW_INFORMATION));
|
|
|
|
if (_displayState[i] == nullptr)
|
|
|
|
{
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
_displayState[i]->Index = (SHORT)i;
|
|
|
|
_displayState[i]->Old = (PCD_IO_CHARACTER)calloc(DisplaySize.right, sizeof(CD_IO_CHARACTER));
|
|
|
|
_displayState[i]->New = (PCD_IO_CHARACTER)calloc(DisplaySize.right, sizeof(CD_IO_CHARACTER));
|
|
|
|
|
|
|
|
if (_displayState[i]->Old == nullptr || _displayState[i]->New == nullptr)
|
|
|
|
{
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
{
|
|
|
|
_displayHeight = DisplaySize.bottom;
|
|
|
|
_displayWidth = DisplaySize.right;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FreeResources(DisplaySize.bottom);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
WDDMConDestroy(_hWddmConCtx);
|
|
|
|
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
WDDMConDestroy(_hWddmConCtx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
hr = E_HANDLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool WddmConEngine::IsInitialized()
|
|
|
|
{
|
|
|
|
return _hWddmConCtx != INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::Enable() noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
RETURN_IF_HANDLE_INVALID(_hWddmConCtx);
|
|
|
|
return WDDMConEnableDisplayAccess((PHANDLE)_hWddmConCtx, TRUE);
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::Disable() noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
RETURN_IF_HANDLE_INVALID(_hWddmConCtx);
|
|
|
|
return WDDMConEnableDisplayAccess((PHANDLE)_hWddmConCtx, FALSE);
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::Invalidate(const SMALL_RECT* const /*psrRegion*/) noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::InvalidateCursor(const COORD* const /*pcoordCursor*/) noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::InvalidateSystem(const RECT* const /*prcDirtyClient*/) noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::InvalidateSelection(const std::vector<SMALL_RECT>& /*rectangles*/) noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::InvalidateScroll(const COORD* const /*pcoordDelta*/) noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::InvalidateAll() noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::InvalidateCircling(_Out_ bool* const pForcePaint) noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
*pForcePaint = false;
|
|
|
|
return S_FALSE;
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::PrepareForTeardown(_Out_ bool* const pForcePaint) noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
*pForcePaint = false;
|
|
|
|
return S_FALSE;
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::StartPaint() noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
RETURN_IF_HANDLE_INVALID(_hWddmConCtx);
|
|
|
|
return WDDMConBeginUpdateDisplayBatch(_hWddmConCtx);
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::EndPaint() noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
RETURN_IF_HANDLE_INVALID(_hWddmConCtx);
|
|
|
|
return WDDMConEndUpdateDisplayBatch(_hWddmConCtx);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Routine Description:
|
|
|
|
// - Used to perform longer running presentation steps outside the lock so the other threads can continue.
|
|
|
|
// - Not currently used by WddmConEngine.
|
|
|
|
// Arguments:
|
|
|
|
// - <none>
|
|
|
|
// Return Value:
|
|
|
|
// - S_FALSE since we do nothing.
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::Present() noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
return S_FALSE;
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::ScrollFrame() noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::PaintBackground() noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
RETURN_IF_HANDLE_INVALID(_hWddmConCtx);
|
|
|
|
|
|
|
|
PCD_IO_CHARACTER OldChar;
|
|
|
|
PCD_IO_CHARACTER NewChar;
|
|
|
|
|
|
|
|
for (LONG rowIndex = 0; rowIndex < _displayHeight; rowIndex++)
|
|
|
|
{
|
|
|
|
for (LONG colIndex = 0; colIndex < _displayWidth; colIndex++)
|
|
|
|
{
|
|
|
|
OldChar = &_displayState[rowIndex]->Old[colIndex];
|
|
|
|
NewChar = &_displayState[rowIndex]->New[colIndex];
|
|
|
|
|
|
|
|
OldChar->Character = NewChar->Character;
|
|
|
|
OldChar->Atribute = NewChar->Atribute;
|
|
|
|
|
|
|
|
NewChar->Character = L' ';
|
|
|
|
NewChar->Atribute = 0x0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::PaintBufferLine(std::basic_string_view<Cluster> const clusters,
|
|
|
|
const COORD coord,
|
|
|
|
const bool /*trimLeft*/) noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
RETURN_IF_HANDLE_INVALID(_hWddmConCtx);
|
|
|
|
|
|
|
|
PCD_IO_CHARACTER OldChar;
|
|
|
|
PCD_IO_CHARACTER NewChar;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < clusters.size() && i < (size_t)_displayWidth; i++)
|
|
|
|
{
|
|
|
|
OldChar = &_displayState[coord.Y]->Old[coord.X + i];
|
|
|
|
NewChar = &_displayState[coord.Y]->New[coord.X + i];
|
|
|
|
|
|
|
|
OldChar->Character = NewChar->Character;
|
|
|
|
OldChar->Atribute = NewChar->Atribute;
|
|
|
|
|
|
|
|
NewChar->Character = clusters.at(i).GetTextAsSingle();
|
|
|
|
NewChar->Atribute = _currentLegacyColorAttribute;
|
|
|
|
}
|
|
|
|
|
|
|
|
return WDDMConUpdateDisplay(_hWddmConCtx, _displayState[coord.Y], FALSE);
|
|
|
|
}
|
|
|
|
CATCH_RETURN();
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::PaintBufferGridLines(GridLines const /*lines*/,
|
|
|
|
COLORREF const /*color*/,
|
|
|
|
size_t const /*cchLine*/,
|
|
|
|
COORD const /*coordTarget*/) noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::PaintSelection(const SMALL_RECT /*rect*/) noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::PaintCursor(const IRenderEngine::CursorOptions& /*options*/) noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::UpdateDrawingBrushes(COLORREF const /*colorForeground*/,
|
|
|
|
COLORREF const /*colorBackground*/,
|
|
|
|
const WORD legacyColorAttribute,
|
Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.
We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.
Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.
## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.
## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
<hr>
* store text with extended attributes too
* Plumb attributes through all the renderers
* parse extended attrs, though we're not renderering them right
* Render these states correctly
* Add a very extensive test
* Cleanup for PR
* a block of PR feedback
* add 512 test cases
* Fix the build
* Fix @carlos-zamora's suggestions
* @miniksa's PR feedback
2019-10-04 22:53:54 +02:00
|
|
|
const ExtendedAttributes /*extendedAttrs*/,
|
2019-06-11 22:27:09 +02:00
|
|
|
bool const /*isSettingDefaultBrushes*/) noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
_currentLegacyColorAttribute = legacyColorAttribute;
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::UpdateFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo) noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
2019-06-01 02:59:07 +02:00
|
|
|
return GetProposedFont(fiFontInfoDesired, fiFontInfo, USER_DEFAULT_SCREEN_DPI);
|
2019-05-03 00:29:04 +02:00
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::UpdateDpi(int const /*iDpi*/) noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
|
|
|
// - This method will update our internal reference for how big the viewport is.
|
|
|
|
// Does nothing for WDDMCon.
|
|
|
|
// Arguments:
|
|
|
|
// - srNewViewport - The bounds of the new viewport.
|
|
|
|
// Return Value:
|
|
|
|
// - HRESULT S_OK
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::UpdateViewport(const SMALL_RECT /*srNewViewport*/) noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::GetProposedFont(const FontInfoDesired& /*fiFontInfoDesired*/,
|
|
|
|
FontInfo& fiFontInfo,
|
|
|
|
int const /*iDpi*/) noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
2019-06-01 02:59:07 +02:00
|
|
|
COORD coordSize = { 0 };
|
|
|
|
LOG_IF_FAILED(GetFontSize(&coordSize));
|
|
|
|
|
|
|
|
fiFontInfo.SetFromEngine(fiFontInfo.GetFaceName(),
|
2019-06-11 22:27:09 +02:00
|
|
|
fiFontInfo.GetFamily(),
|
|
|
|
fiFontInfo.GetWeight(),
|
|
|
|
fiFontInfo.IsTrueTypeFont(),
|
|
|
|
coordSize,
|
|
|
|
coordSize);
|
2019-06-01 02:59:07 +02:00
|
|
|
|
2019-05-03 00:29:04 +02:00
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
SMALL_RECT WddmConEngine::GetDirtyRectInChars()
|
|
|
|
{
|
|
|
|
SMALL_RECT r;
|
|
|
|
r.Bottom = _displayHeight > 0 ? (SHORT)(_displayHeight - 1) : 0;
|
|
|
|
r.Top = 0;
|
|
|
|
r.Left = 0;
|
|
|
|
r.Right = _displayWidth > 0 ? (SHORT)(_displayWidth - 1) : 0;
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
RECT WddmConEngine::GetDisplaySize()
|
|
|
|
{
|
|
|
|
RECT r;
|
|
|
|
r.top = 0;
|
|
|
|
r.left = 0;
|
|
|
|
r.bottom = _displayHeight;
|
|
|
|
r.right = _displayWidth;
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::GetFontSize(_Out_ COORD* const pFontSize) noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
// In order to retrieve the font size being used by DirectX, it is necessary
|
|
|
|
// to modify the API set that defines the contract for WddmCon. However, the
|
|
|
|
// intention is to subsume WddmCon into ConhostV2 directly once the issue of
|
|
|
|
// building in the OneCore 'depot' including DirectX headers and libs is
|
|
|
|
// resolved. The font size has no bearing on the behavior of the console
|
|
|
|
// since it is used to determine the invalid rectangle whenever the console
|
|
|
|
// buffer changes. However, given that no invalidation logic exists for this
|
|
|
|
// renderer, the value returned by this function is irrelevant.
|
|
|
|
//
|
|
|
|
// TODO: MSFT 11851921 - Subsume WddmCon into ConhostV2 and remove the API
|
|
|
|
// set extension.
|
|
|
|
COORD c;
|
|
|
|
c.X = DEFAULT_FONT_WIDTH;
|
|
|
|
c.Y = DEFAULT_FONT_HEIGHT;
|
|
|
|
|
|
|
|
*pFontSize = c;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::IsGlyphWideByFont(const std::wstring_view /*glyph*/, _Out_ bool* const pResult) noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
*pResult = false;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
|
|
|
// - Updates the window's title string.
|
|
|
|
// Does nothing for WddmCon.
|
|
|
|
// Arguments:
|
|
|
|
// - newTitle: the new string to use for the title of the window
|
|
|
|
// Return Value:
|
|
|
|
// - S_OK
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT WddmConEngine::_DoUpdateTitle(_In_ const std::wstring& /*newTitle*/) noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
return S_OK;
|
|
|
|
}
|