terminal/src/renderer/uia/UiaRenderer.cpp
Leonard Hecker 9cb4fc4373 wip
2021-10-10 20:31:03 +02:00

474 lines
14 KiB
C++

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "precomp.h"
#include "UiaRenderer.hpp"
#pragma hdrstop
using namespace Microsoft::Console::Render;
using namespace Microsoft::Console::Types;
// Routine Description:
// - Constructs a UIA engine for console text
// which primarily notifies automation clients of any activity
UiaEngine::UiaEngine(IUiaEventDispatcher* dispatcher) :
_dispatcher{ THROW_HR_IF_NULL(E_INVALIDARG, dispatcher) },
_isPainting{ false },
_selectionChanged{ false },
_textBufferChanged{ false },
_cursorChanged{ false },
_isEnabled{ true },
_prevSelection{},
_prevCursorRegion{},
RenderEngineBase()
{
}
// Routine Description:
// - Sets this engine to enabled allowing presentation to occur
// Arguments:
// - <none>
// Return Value:
// - S_OK
[[nodiscard]] HRESULT UiaEngine::Enable() noexcept
{
_isEnabled = true;
return S_OK;
}
// Routine Description:
// - Sets this engine to disabled to prevent presentation from occurring
// Arguments:
// - <none>
// Return Value:
// - S_OK
[[nodiscard]] HRESULT UiaEngine::Disable() noexcept
{
_isEnabled = false;
return S_OK;
}
// Routine Description:
// - Notifies us that the console has changed the character region specified.
// - NOTE: This typically triggers on cursor or text buffer changes
// Arguments:
// - psrRegion - Character region (SMALL_RECT) that has been changed
// Return Value:
// - S_OK, else an appropriate HRESULT for failing to allocate or write.
[[nodiscard]] HRESULT UiaEngine::Invalidate(const SMALL_RECT* const /*psrRegion*/) noexcept
{
_textBufferChanged = true;
return S_OK;
}
// Routine Description:
// - Notifies us that the console has changed the position of the cursor.
// For UIA, this doesn't mean anything. So do nothing.
// Arguments:
// - psrRegion - the region covered by the cursor
// Return Value:
// - S_OK
[[nodiscard]] HRESULT UiaEngine::InvalidateCursor(const SMALL_RECT* const psrRegion) noexcept
try
{
RETURN_HR_IF_NULL(E_INVALIDARG, psrRegion);
// check if cursor moved
if (*psrRegion != _prevCursorRegion)
{
_prevCursorRegion = *psrRegion;
_cursorChanged = true;
}
return S_OK;
}
CATCH_RETURN();
// Routine Description:
// - Invalidates a rectangle describing a pixel area on the display
// For UIA, this doesn't mean anything. So do nothing.
// Arguments:
// - prcDirtyClient - pixel rectangle
// Return Value:
// - S_FALSE
[[nodiscard]] HRESULT UiaEngine::InvalidateSystem(const RECT* const /*prcDirtyClient*/) noexcept
{
return S_FALSE;
}
// Routine Description:
// - Notifies us that the console has changed the selection region and would
// like it updated
// Arguments:
// - rectangles - One or more rectangles describing character positions on the grid
// Return Value:
// - S_OK
[[nodiscard]] HRESULT UiaEngine::InvalidateSelection(const std::vector<SMALL_RECT>& rectangles) noexcept
{
// early exit: different number of rows
if (_prevSelection.size() != rectangles.size())
{
try
{
_selectionChanged = true;
_prevSelection = rectangles;
}
CATCH_LOG_RETURN_HR(E_FAIL);
return S_OK;
}
for (size_t i = 0; i < rectangles.size(); i++)
{
try
{
const auto prevRect = _prevSelection.at(i);
const auto newRect = rectangles.at(i);
// if any value is different, selection has changed
if (prevRect.Top != newRect.Top || prevRect.Right != newRect.Right || prevRect.Left != newRect.Left || prevRect.Bottom != newRect.Bottom)
{
_selectionChanged = true;
_prevSelection = rectangles;
return S_OK;
}
}
CATCH_LOG_RETURN_HR(E_FAIL);
}
// assume selection has not changed
_selectionChanged = false;
return S_OK;
}
// Routine Description:
// - Scrolls the existing dirty region (if it exists) and
// invalidates the area that is uncovered in the window.
// Arguments:
// - pcoordDelta - The number of characters to move and uncover.
// - -Y is up, Y is down, -X is left, X is right.
// Return Value:
// - S_OK
[[nodiscard]] HRESULT UiaEngine::InvalidateScroll(const COORD* const /*pcoordDelta*/) noexcept
{
return S_FALSE;
}
// Routine Description:
// - Notifies to repaint everything.
// - NOTE: Use sparingly. Only use when something that could affect the entire
// frame simultaneously occurs.
// Arguments:
// - <none>
// Return Value:
// - S_OK, else an appropriate HRESULT for failing to allocate or write.
[[nodiscard]] HRESULT UiaEngine::InvalidateAll() noexcept
{
_textBufferChanged = true;
return S_OK;
}
// Routine Description:
// - This currently has no effect in this renderer.
// Arguments:
// - pForcePaint - Always filled with false
// Return Value:
// - S_FALSE because we don't use this.
[[nodiscard]] HRESULT UiaEngine::InvalidateCircling(_Out_ bool* const pForcePaint) noexcept
{
RETURN_HR_IF_NULL(E_INVALIDARG, pForcePaint);
*pForcePaint = false;
return S_FALSE;
}
// Routine Description:
// - This is unused by this renderer.
// Arguments:
// - pForcePaint - always filled with false.
// Return Value:
// - S_FALSE because this is unused.
[[nodiscard]] HRESULT UiaEngine::PrepareForTeardown(_Out_ bool* const pForcePaint) noexcept
{
RETURN_HR_IF_NULL(E_INVALIDARG, pForcePaint);
*pForcePaint = false;
return S_FALSE;
}
// Routine Description:
// - Prepares internal structures for a painting operation.
// Arguments:
// - <none>
// Return Value:
// - S_OK if we started to paint. S_FALSE if we didn't need to paint.
[[nodiscard]] HRESULT UiaEngine::StartPaint() noexcept
{
RETURN_HR_IF(S_FALSE, !_isEnabled);
// add more events here
const bool somethingToDo = _selectionChanged || _textBufferChanged || _cursorChanged;
// If there's nothing to do, quick return
RETURN_HR_IF(S_FALSE, !somethingToDo);
_isPainting = true;
return S_OK;
}
// Routine Description:
// - Ends batch drawing and notifies automation clients of updated regions
// Arguments:
// - <none>
// Return Value:
// - S_OK, else an appropriate HRESULT for failing to allocate or write.
[[nodiscard]] HRESULT UiaEngine::EndPaint() noexcept
{
RETURN_HR_IF(S_FALSE, !_isEnabled);
RETURN_HR_IF(E_INVALIDARG, !_isPainting); // invalid to end paint when we're not painting
// Fire UIA Events here
if (_selectionChanged)
{
try
{
_dispatcher->SignalSelectionChanged();
}
CATCH_LOG();
}
if (_textBufferChanged)
{
try
{
_dispatcher->SignalTextChanged();
}
CATCH_LOG();
}
if (_cursorChanged)
{
try
{
_dispatcher->SignalCursorChanged();
}
CATCH_LOG();
}
_selectionChanged = false;
_textBufferChanged = false;
_cursorChanged = false;
_isPainting = false;
return S_OK;
}
// RenderEngineBase defines a WaitUntilCanRender() that sleeps for 8ms to throttle rendering.
// But UiaEngine is never the only the engine running. Overriding this function prevents
// us from sleeping 16ms per frame, when the other engine also sleeps for 8ms.
void UiaEngine::WaitUntilCanRender() noexcept
{
}
// Routine Description:
// - Used to perform longer running presentation steps outside the lock so the
// other threads can continue.
// - Not currently used by UiaEngine.
// Arguments:
// - <none>
// Return Value:
// - S_FALSE since we do nothing.
[[nodiscard]] HRESULT UiaEngine::Present() noexcept
{
return S_FALSE;
}
// Routine Description:
// - This is currently unused.
// Arguments:
// - <none>
// Return Value:
// - S_FALSE
[[nodiscard]] HRESULT UiaEngine::ScrollFrame() noexcept
{
return S_FALSE;
}
// Routine Description:
// - Paints the background of the invalid area of the frame.
// For UIA, this doesn't mean anything. So do nothing.
// Arguments:
// - <none>
// Return Value:
// - S_FALSE since we do nothing
[[nodiscard]] HRESULT UiaEngine::PaintBackground() noexcept
{
return S_FALSE;
}
// Routine Description:
// - Places one line of text onto the screen at the given position
// For UIA, this doesn't mean anything. So do nothing.
// Arguments:
// - clusters - Iterable collection of cluster information (text and columns it should consume)
// - coord - Character coordinate position in the cell grid
// - fTrimLeft - Whether or not to trim off the left half of a double wide character
// Return Value:
// - S_FALSE
[[nodiscard]] HRESULT UiaEngine::PaintBufferLine(gsl::span<const Cluster> const /*clusters*/,
COORD const /*coord*/,
const bool /*trimLeft*/,
const bool /*lineWrapped*/) noexcept
{
return S_FALSE;
}
// Routine Description:
// - Paints lines around cells (draws in pieces of the grid)
// For UIA, this doesn't mean anything. So do nothing.
// Arguments:
// - lines - <unused>
// - color - <unused>
// - cchLine - <unused>
// - coordTarget - <unused>
// Return Value:
// - S_FALSE
[[nodiscard]] HRESULT UiaEngine::PaintBufferGridLines(GridLineSet const /*lines*/,
COLORREF const /*color*/,
size_t const /*cchLine*/,
COORD const /*coordTarget*/) noexcept
{
return S_FALSE;
}
// Routine Description:
// - Reads the selected area, selection mode, and active screen buffer
// from the global properties and dispatches a GDI invert on the selected text area.
// Because the selection is the responsibility of the terminal, and not the
// host, render nothing.
// Arguments:
// - rect - Rectangle to invert or highlight to make the selection area
// Return Value:
// - S_FALSE
[[nodiscard]] HRESULT UiaEngine::PaintSelection(const SMALL_RECT /*rect*/) noexcept
{
return S_FALSE;
}
// Routine Description:
// - Draws the cursor on the screen
// For UIA, this doesn't mean anything. So do nothing.
// Arguments:
// - options - Packed options relevant to how to draw the cursor
// Return Value:
// - S_FALSE
[[nodiscard]] HRESULT UiaEngine::PaintCursor(const CursorOptions& /*options*/) noexcept
{
return S_FALSE;
}
// Routine Description:
// - Updates the default brush colors used for drawing
// For UIA, this doesn't mean anything. So do nothing.
// Arguments:
// - textAttributes - <unused>
// - pData - <unused>
// - usingSoftFont - <unused>
// - isSettingDefaultBrushes - <unused>
// Return Value:
// - S_FALSE since we do nothing
[[nodiscard]] HRESULT UiaEngine::UpdateDrawingBrushes(const TextAttribute& /*textAttributes*/,
const gsl::not_null<IRenderData*> /*pData*/,
const bool /*usingSoftFont*/,
const bool /*isSettingDefaultBrushes*/) noexcept
{
return S_FALSE;
}
// Routine Description:
// - Updates the font used for drawing
// Arguments:
// - pfiFontInfoDesired - <unused>
// - fiFontInfo - <unused>
// Return Value:
// - S_FALSE since we do nothing
[[nodiscard]] HRESULT UiaEngine::UpdateFont(const FontInfoDesired& /*pfiFontInfoDesired*/, FontInfo& /*fiFontInfo*/) noexcept
{
return S_FALSE;
}
// Routine Description:
// - Sets the DPI in this renderer
// - Not currently used by UiaEngine.
// Arguments:
// - iDpi - DPI
// Return Value:
// - S_OK
[[nodiscard]] HRESULT UiaEngine::UpdateDpi(int const /*iDpi*/) noexcept
{
return S_FALSE;
}
// Method Description:
// - This method will update our internal reference for how big the viewport is.
// Arguments:
// - srNewViewport - The bounds of the new viewport.
// Return Value:
// - HRESULT S_OK
[[nodiscard]] HRESULT UiaEngine::UpdateViewport(const SMALL_RECT /*srNewViewport*/) noexcept
{
return S_FALSE;
}
// Routine Description:
// - Currently unused by this renderer
// Arguments:
// - pfiFontInfoDesired - <unused>
// - pfiFontInfo - <unused>
// - iDpi - <unused>
// Return Value:
// - S_FALSE
[[nodiscard]] HRESULT UiaEngine::GetProposedFont(const FontInfoDesired& /*pfiFontInfoDesired*/,
FontInfo& /*pfiFontInfo*/,
int const /*iDpi*/) noexcept
{
return S_FALSE;
}
// Routine Description:
// - Gets the area that we currently believe is dirty within the character cell grid
// - Not currently used by UiaEngine.
// Arguments:
// - area - Rectangle describing dirty area in characters.
// Return Value:
// - S_OK.
[[nodiscard]] HRESULT UiaEngine::GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept
{
// Magic static is only valid because any instance of this object has the same behavior.
// Use member variable instead if this ever changes.
const static til::rectangle empty;
area = { &empty, 1 };
return S_OK;
}
// Routine Description:
// - Gets the current font size
// Arguments:
// - pFontSize - Filled with the font size.
// Return Value:
// - S_OK
[[nodiscard]] HRESULT UiaEngine::GetFontSize(_Out_ COORD* const /*pFontSize*/) noexcept
{
return S_FALSE;
}
// Method Description:
// - Updates the window's title string.
// - Currently unused by this renderer.
// Arguments:
// - newTitle: the new string to use for the title of the window
// Return Value:
// - S_FALSE
[[nodiscard]] HRESULT UiaEngine::_DoUpdateTitle(_In_ const std::wstring_view /*newTitle*/) noexcept
{
return S_FALSE;
}