4c53c595e7
This PR adds support for the VT line rendition attributes, which allow for double-width and double-height line renditions. These renditions are enabled with the `DECDWL` (double-width line) and `DECDHL` (double-height line) escape sequences. Both reset to the default rendition with the `DECSWL` (single-width line) escape sequence. For now this functionality is only supported by the GDI renderer in conhost. There are a lot of changes, so this is just a general overview of the main areas affected. Previously it was safe to assume that the screen had a fixed width, at least for a given point in time. But now we need to deal with the possibility of different lines have different widths, so all the functions that are constrained by the right border (text wrapping, cursor movement operations, and sequences like `EL` and `ICH`) now need to lookup the width of the active line in order to behave correctly. Similarly it used to be safe to assume that buffer and screen coordinates were the same thing, but that is no longer true. Lots of places now need to translate back and forth between coordinate systems dependent on the line rendition. This includes clipboard handling, the conhost color selection and search, accessibility location tracking and screen reading, IME editor positioning, "snapping" the viewport, and of course all the rendering calculations. For the rendering itself, I've had to introduce a new `PrepareLineTransform` method that the render engines can use to setup the necessary transform matrix for a given line rendition. This is also now used to handle the horizontal viewport offset, since that could no longer be achieved just by changing the target coordinates (on a double width line, the viewport offset may be halfway through a character). I've also had to change the renderer's existing `InvalidateCursor` method to take a `SMALL_RECT` rather than a `COORD`, to allow for the cursor being a variable width. Technically this was already a problem, because the cursor could occupy two screen cells when over a double-width character, but now it can be anything between one and four screen cells (e.g. a double-width character on the double-width line). In terms of architectural changes, there is now a new `lineRendition` field in the `ROW` class that keeps track of the line rendition for each row, and several new methods in the `ROW` and `TextBuffer` classes for manipulating that state. This includes a few helper methods for handling the various issues discussed above, e.g. position clamping and translating between coordinate systems. ## Validation Steps Performed I've manually confirmed all the double-width and double-height tests in _Vttest_ are now working as expected, and the _VT100 Torture Test_ now renders correctly (at least the line rendition aspects). I've also got my own test scripts that check many of the line rendition boundary cases and have confirmed that those are now passing. I've manually tested as many areas of the conhost UI that I could think of, that might be affected by line rendition, including things like searching, selection, copying, and color highlighting. For accessibility, I've confirmed that the _Magnifier_ and _Narrator_ correctly handle double-width lines. And I've also tested the Japanese IME, which while not perfect, is at least useable. Closes #7865
90 lines
4.2 KiB
C++
90 lines
4.2 KiB
C++
/*++
|
|
Copyright (c) Microsoft Corporation
|
|
Licensed under the MIT license.
|
|
|
|
Module Name:
|
|
- BgfxEngine.hpp
|
|
|
|
Abstract:
|
|
- OneCore implementation of the IRenderEngine interface.
|
|
|
|
Author(s):
|
|
- Hernan Gatta (HeGatta) 29-Mar-2017
|
|
--*/
|
|
|
|
// Typically, renderers live under the renderer/xxx top-level folder. This
|
|
// renderer however has strong ties to the interactivity library. More
|
|
// specifically, it makes use of the Console IO Server communication class.
|
|
// It is also a one-file renderer and I had problems with header file
|
|
// definitions. Placing this renderer in the OneCore Interactivity library fixes
|
|
// the header issues, and is more sensible given its ties to ConIoSrv.
|
|
// (hegatta, 2017)
|
|
|
|
#pragma once
|
|
|
|
#include "../../renderer/inc/RenderEngineBase.hpp"
|
|
|
|
namespace Microsoft::Console::Render
|
|
{
|
|
class BgfxEngine final : public RenderEngineBase
|
|
{
|
|
public:
|
|
BgfxEngine(PVOID SharedViewBase, LONG DisplayHeight, LONG DisplayWidth, LONG FontWidth, LONG FontHeight);
|
|
~BgfxEngine() override = default;
|
|
|
|
// IRenderEngine Members
|
|
[[nodiscard]] HRESULT Invalidate(const SMALL_RECT* const psrRegion) noexcept override;
|
|
[[nodiscard]] HRESULT InvalidateCursor(const SMALL_RECT* const psrRegion) noexcept override;
|
|
[[nodiscard]] HRESULT InvalidateSystem(const RECT* const prcDirtyClient) noexcept override;
|
|
[[nodiscard]] HRESULT InvalidateSelection(const std::vector<SMALL_RECT>& rectangles) noexcept override;
|
|
[[nodiscard]] HRESULT InvalidateScroll(const COORD* const pcoordDelta) noexcept override;
|
|
[[nodiscard]] HRESULT InvalidateAll() noexcept override;
|
|
[[nodiscard]] HRESULT InvalidateCircling(_Out_ bool* const pForcePaint) noexcept override;
|
|
[[nodiscard]] HRESULT PrepareForTeardown(_Out_ bool* const pForcePaint) noexcept override;
|
|
|
|
[[nodiscard]] HRESULT StartPaint() noexcept override;
|
|
[[nodiscard]] HRESULT EndPaint() noexcept override;
|
|
[[nodiscard]] HRESULT Present() noexcept override;
|
|
|
|
[[nodiscard]] HRESULT ScrollFrame() noexcept override;
|
|
|
|
[[nodiscard]] HRESULT PaintBackground() noexcept override;
|
|
[[nodiscard]] HRESULT PaintBufferLine(const gsl::span<const Cluster> clusters,
|
|
const COORD coord,
|
|
const bool trimLeft,
|
|
const bool lineWrapped) noexcept override;
|
|
[[nodiscard]] HRESULT PaintBufferGridLines(GridLines const lines, COLORREF const color, size_t const cchLine, COORD const coordTarget) noexcept override;
|
|
[[nodiscard]] HRESULT PaintSelection(const SMALL_RECT rect) noexcept override;
|
|
|
|
[[nodiscard]] HRESULT PaintCursor(const CursorOptions& options) noexcept override;
|
|
|
|
[[nodiscard]] HRESULT UpdateDrawingBrushes(const TextAttribute& textAttributes,
|
|
const gsl::not_null<IRenderData*> pData,
|
|
bool const isSettingDefaultBrushes) noexcept override;
|
|
[[nodiscard]] HRESULT UpdateFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo) noexcept override;
|
|
[[nodiscard]] HRESULT UpdateDpi(int const iDpi) noexcept override;
|
|
[[nodiscard]] HRESULT UpdateViewport(const SMALL_RECT srNewViewport) noexcept override;
|
|
|
|
[[nodiscard]] HRESULT GetProposedFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo, int const iDpi) noexcept override;
|
|
|
|
[[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override;
|
|
[[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) noexcept override;
|
|
[[nodiscard]] HRESULT IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept override;
|
|
|
|
protected:
|
|
[[nodiscard]] HRESULT _DoUpdateTitle(_In_ const std::wstring_view newTitle) noexcept override;
|
|
|
|
private:
|
|
ULONG_PTR _sharedViewBase;
|
|
SIZE_T _runLength;
|
|
|
|
LONG _displayHeight;
|
|
LONG _displayWidth;
|
|
til::rectangle _dirtyArea;
|
|
|
|
COORD _fontSize;
|
|
|
|
WORD _currentLegacyColorAttribute;
|
|
};
|
|
}
|