terminal/src/host/conareainfo.cpp
Dustin L. Howett 80da24ecf8
Replace basic_string_view<T> with span<const T> (#6921)
We were using std::basic_string_view as a stand-in for std::span so that
we could change over all at once when C++20 dropped with full span
support. That day's not here yet, but as of 54a7fce3e we're using GSL 3,
whose span is C++20-compliant.

This commit replaces every instance of basic_string_view that was not
referring to an actual string with a span of the appropriate type.

I moved the `const` qualifier into span's `T` because while
`basic_string_view.at()` returns `const T&`, `span.at()` returns `T&`
(without the const). I wanted to maintain the invariant that members of
the span were immutable.

* Mechanical Changes
   * `sv.at(x)` -> `gsl::at(sp, x)`
   * `sv.c{begin,end}` -> `sp.{begin,end}` (span's iterators are const)

I had to replace a `std::basic_string<>` with a `std::vector<>` in
ConImeInfo, and I chose to replace a manual array walk in
ScreenInfoUiaProviderBase with a ranged-for. Please review those
specifically.

This will almost certainly cause a code size regression in Windows
because I'm blowing out all the PGO counts. Whoops.

Related: #3956, #975.
2020-07-15 16:40:42 +00:00

224 lines
7.4 KiB
C++

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "precomp.h"
#include "conareainfo.h"
#include "_output.h"
#include "../interactivity/inc/ServiceLocator.hpp"
#include "../types/inc/viewport.hpp"
#pragma hdrstop
using namespace Microsoft::Console::Types;
using Microsoft::Console::Interactivity::ServiceLocator;
ConversionAreaBufferInfo::ConversionAreaBufferInfo(const COORD coordBufferSize) :
coordCaBuffer(coordBufferSize),
rcViewCaWindow({ 0 }),
coordConView({ 0 })
{
}
ConversionAreaInfo::ConversionAreaInfo(const COORD bufferSize,
const COORD windowSize,
const TextAttribute& fill,
const TextAttribute& popupFill,
const FontInfo fontInfo) :
_caInfo{ bufferSize },
_isHidden{ true },
_screenBuffer{ nullptr }
{
SCREEN_INFORMATION* pNewScreen = nullptr;
// cursor has no height because it won't be rendered for conversion area
THROW_IF_NTSTATUS_FAILED(SCREEN_INFORMATION::CreateInstance(windowSize,
fontInfo,
bufferSize,
fill,
popupFill,
0,
&pNewScreen));
// Suppress painting notifications for modifying a conversion area cursor as they're not actually rendered.
pNewScreen->GetTextBuffer().GetCursor().SetIsConversionArea(true);
pNewScreen->ConvScreenInfo = this;
_screenBuffer.reset(pNewScreen);
}
ConversionAreaInfo::ConversionAreaInfo(ConversionAreaInfo&& other) :
_caInfo(other._caInfo),
_isHidden(other._isHidden),
_screenBuffer(nullptr)
{
std::swap(_screenBuffer, other._screenBuffer);
}
// Routine Description:
// - Describes whether the conversion area should be drawn or should be hidden.
// Arguments:
// - <none>
// Return Value:
// - True if it should not be drawn. False if it should be drawn.
bool ConversionAreaInfo::IsHidden() const noexcept
{
return _isHidden;
}
// Routine Description:
// - Sets a value describing whether the conversion area should be drawn or should be hidden.
// Arguments:
// - fIsHidden - True if it should not be drawn. False if it should be drawn.
// Return Value:
// - <none>
void ConversionAreaInfo::SetHidden(const bool fIsHidden) noexcept
{
_isHidden = fIsHidden;
}
// Routine Description:
// - Retrieves the underlying text buffer for use in rendering data
const TextBuffer& ConversionAreaInfo::GetTextBuffer() const noexcept
{
return _screenBuffer->GetTextBuffer();
}
// Routine Description:
// - Retrieves the layout/overlay information about where to place this conversion area relative to the
// existing screen buffers and viewports.
const ConversionAreaBufferInfo& ConversionAreaInfo::GetAreaBufferInfo() const noexcept
{
return _caInfo;
}
// Routine Description:
// - Forwards a color attribute setting request to the internal screen information
// Arguments:
// - attr - Color to apply to internal screen buffer
void ConversionAreaInfo::SetAttributes(const TextAttribute& attr)
{
_screenBuffer->SetAttributes(attr);
}
// Routine Description:
// - Writes text into the conversion area. Since conversion areas are only
// one line, you can only specify the column to write.
// Arguments:
// - text - Text to insert into the conversion area buffer
// - column - Column to start at (X position)
void ConversionAreaInfo::WriteText(const std::vector<OutputCell>& text,
const SHORT column)
{
gsl::span<const OutputCell> view(text.data(), text.size());
_screenBuffer->Write(view, { column, 0 });
}
// Routine Description:
// - Clears out a conversion area
void ConversionAreaInfo::ClearArea() noexcept
{
SetHidden(true);
try
{
_screenBuffer->ClearTextData();
}
CATCH_LOG();
Paint();
}
[[nodiscard]] HRESULT ConversionAreaInfo::Resize(const COORD newSize) noexcept
{
// attempt to resize underlying buffers
RETURN_IF_NTSTATUS_FAILED(_screenBuffer->ResizeScreenBuffer(newSize, FALSE));
// store new size
_caInfo.coordCaBuffer = newSize;
// restrict viewport to buffer size.
const COORD restriction = { newSize.X - 1i16, newSize.Y - 1i16 };
_caInfo.rcViewCaWindow.Left = std::min(_caInfo.rcViewCaWindow.Left, restriction.X);
_caInfo.rcViewCaWindow.Right = std::min(_caInfo.rcViewCaWindow.Right, restriction.X);
_caInfo.rcViewCaWindow.Top = std::min(_caInfo.rcViewCaWindow.Top, restriction.Y);
_caInfo.rcViewCaWindow.Bottom = std::min(_caInfo.rcViewCaWindow.Bottom, restriction.Y);
return S_OK;
}
void ConversionAreaInfo::SetWindowInfo(const SMALL_RECT view) noexcept
{
if (view.Left != _caInfo.rcViewCaWindow.Left ||
view.Top != _caInfo.rcViewCaWindow.Top ||
view.Right != _caInfo.rcViewCaWindow.Right ||
view.Bottom != _caInfo.rcViewCaWindow.Bottom)
{
if (!IsHidden())
{
SetHidden(true);
Paint();
_caInfo.rcViewCaWindow = view;
SetHidden(false);
Paint();
}
else
{
_caInfo.rcViewCaWindow = view;
}
}
}
void ConversionAreaInfo::SetViewPos(const COORD pos) noexcept
{
if (IsHidden())
{
_caInfo.coordConView = pos;
}
else
{
CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
SMALL_RECT OldRegion = _caInfo.rcViewCaWindow;
OldRegion.Left += _caInfo.coordConView.X;
OldRegion.Right += _caInfo.coordConView.X;
OldRegion.Top += _caInfo.coordConView.Y;
OldRegion.Bottom += _caInfo.coordConView.Y;
WriteToScreen(gci.GetActiveOutputBuffer(), Viewport::FromInclusive(OldRegion));
_caInfo.coordConView = pos;
SMALL_RECT NewRegion = _caInfo.rcViewCaWindow;
NewRegion.Left += _caInfo.coordConView.X;
NewRegion.Right += _caInfo.coordConView.X;
NewRegion.Top += _caInfo.coordConView.Y;
NewRegion.Bottom += _caInfo.coordConView.Y;
WriteToScreen(gci.GetActiveOutputBuffer(), Viewport::FromInclusive(NewRegion));
}
}
void ConversionAreaInfo::Paint() const noexcept
{
CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
SCREEN_INFORMATION& ScreenInfo = gci.GetActiveOutputBuffer();
const auto viewport = ScreenInfo.GetViewport();
SMALL_RECT WriteRegion;
WriteRegion.Left = viewport.Left() + _caInfo.coordConView.X + _caInfo.rcViewCaWindow.Left;
WriteRegion.Right = WriteRegion.Left + (_caInfo.rcViewCaWindow.Right - _caInfo.rcViewCaWindow.Left);
WriteRegion.Top = viewport.Top() + _caInfo.coordConView.Y + _caInfo.rcViewCaWindow.Top;
WriteRegion.Bottom = WriteRegion.Top + (_caInfo.rcViewCaWindow.Bottom - _caInfo.rcViewCaWindow.Top);
if (!IsHidden())
{
WriteConvRegionToScreen(ScreenInfo, Viewport::FromInclusive(WriteRegion));
}
else
{
WriteToScreen(ScreenInfo, Viewport::FromInclusive(WriteRegion));
}
}