Files
terminal/src/buffer/out/OutputCellView.cpp
Leonard Hecker a01500f051 Rewrite ROW to be Unicode capable (#13626)
This commit is a from-scratch rewrite of `ROW` with the primary goal to get
rid of the rather bodgy `UnicodeStorage` class and improve Unicode support.

Previously a 120x9001 terminal buffer would store a vector of 9001 `ROW`s
where each `ROW` stored exactly 120 `wchar_t`. Glyphs exceeding their
allocated space would be stored in the `UnicodeStorage` which was basically
a `hashmap<Coordinate, String>`. Iterating over the text in a `ROW` would
require us to check each glyph and fetch it from the map conditionally.
On newlines we'd have to invalidate all map entries that are now gone,
so for every invalidated `ROW` we'd iterate through all glyphs again and if
a single one was stored in `UnicodeStorage`, we'd then iterate through the
entire hashmap to remove all coordinates that were residing on that `ROW`.
All in all, this wasn't the most robust nor performant code.

The new implementation is simple (from a design perspective):
Store all text in a `ROW` in a regular string. Grow the string if needed.
The association between columns and text works by storing character offsets
in a column-wide array. This algorithm is <100 LOC and removes ~1000.

As an aside this PR does a few more things that go hand in hand:
* Remove most of `ROW` helper classes, which aren't needed anymore.
* Allocate backing memory in a single `VirtualAlloc` call.
* Rewrite `IsCursorDoubleWidth` to use `DbcsAttrAt` directly.
  Improves overall performance by 10-20% and makes this implementation
  faster than the previous NxM storage, despite the added complexity.

Part of #8000

## Validation Steps Performed
* Existing and new unit and feature tests complete 
* Printing Unicode completes without crashing 
* Resizing works without crashing 
2022-11-11 20:34:58 +01:00

97 lines
3.1 KiB
C++

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "precomp.h"
#include "OutputCellView.hpp"
// Routine Description:
// - Constructs a read-only view of data formatted as a single output buffer cell
// Arguments:
// - view - String data for the text displayed on screen
// - dbcsAttr - Describes column width information (double byte character data)
// - textAttr - Describes color and formatting data
// - behavior - Describes where to retrieve color/format data. From this view? From defaults? etc.
OutputCellView::OutputCellView(const std::wstring_view view,
const DbcsAttribute dbcsAttr,
const TextAttribute textAttr,
const TextAttributeBehavior behavior) noexcept :
_view(view),
_dbcsAttr(dbcsAttr),
_textAttr(textAttr),
_behavior(behavior)
{
}
// Routine Description:
// - Returns reference to view over text data
// Return Value:
// - Reference to UTF-16 character data
// C26445 - suppressed to enable the `TextBufferTextIterator::operator->` method which needs a non-temporary memory location holding the wstring_view.
// TODO: GH 2681 - remove this suppression by reconciling the probably bad design of the iterators that leads to this being required.
[[gsl::suppress(26445)]] const std::wstring_view& OutputCellView::Chars() const noexcept
{
return _view;
}
// Routine Description:
// - Reports how many columns we expect the Chars() text data to consume
// Return Value:
// - Count of column cells on the screen
til::CoordType OutputCellView::Columns() const noexcept
{
return DbcsAttr() == DbcsAttribute::Leading ? 2 : 1;
}
// Routine Description:
// - Retrieves character cell width data
// Return Value:
// - DbcsAttribute data
DbcsAttribute OutputCellView::DbcsAttr() const noexcept
{
return _dbcsAttr;
}
// Routine Description:
// - Retrieves text color/formatting information
// Return Value:
// - TextAttribute with encoded formatting data
TextAttribute OutputCellView::TextAttr() const noexcept
{
return _textAttr;
}
// Routine Description:
// - Retrieves behavior for inserting this cell into the buffer. See enum for details.
// Return Value:
// - TextAttributeBehavior enum value
TextAttributeBehavior OutputCellView::TextAttrBehavior() const noexcept
{
return _behavior;
}
// Routine Description:
// - Compares two views
// Arguments:
// - it - Other view to compare to this one
// Return Value:
// - True if all contents/references are equal. False otherwise.
bool OutputCellView::operator==(const OutputCellView& it) const noexcept
{
return _view == it._view &&
_dbcsAttr == it._dbcsAttr &&
_textAttr == it._textAttr &&
_behavior == it._behavior;
}
// Routine Description:
// - Compares two views for inequality
// Arguments:
// - it - Other view to compare tot his one.
// Return Value:
// - True if any contents or references are inequal. False if they're all equal.
bool OutputCellView::operator!=(const OutputCellView& it) const noexcept
{
return !(*this == it);
}