325 lines
8.3 KiB
C++
325 lines
8.3 KiB
C++
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT license.
|
|
|
|
#include "precomp.h"
|
|
|
|
#include "CharRow.hpp"
|
|
#include "unicode.hpp"
|
|
#include "Row.hpp"
|
|
|
|
// Routine Description:
|
|
// - constructor
|
|
// Arguments:
|
|
// - rowWidth - the size (in wchar_t) of the char and attribute rows
|
|
// - pParent - the parent ROW
|
|
// Return Value:
|
|
// - instantiated object
|
|
// Note: will through if unable to allocate char/attribute buffers
|
|
CharRow::CharRow(size_t rowWidth, ROW* const pParent) :
|
|
_wrapForced{ false },
|
|
_doubleBytePadded{ false },
|
|
_data(rowWidth, value_type()),
|
|
_pParent{ FAIL_FAST_IF_NULL(pParent) }
|
|
{
|
|
}
|
|
|
|
// Routine Description:
|
|
// - Sets the wrap status for the current row
|
|
// Arguments:
|
|
// - wrapForced - True if the row ran out of space and we forced to wrap to the next row. False otherwise.
|
|
// Return Value:
|
|
// - <none>
|
|
void CharRow::SetWrapForced(const bool wrapForced) noexcept
|
|
{
|
|
_wrapForced = wrapForced;
|
|
}
|
|
|
|
// Routine Description:
|
|
// - Gets the wrap status for the current row
|
|
// Arguments:
|
|
// - <none>
|
|
// Return Value:
|
|
// - True if the row ran out of space and we were forced to wrap to the next row. False otherwise.
|
|
bool CharRow::WasWrapForced() const noexcept
|
|
{
|
|
return _wrapForced;
|
|
}
|
|
|
|
// Routine Description:
|
|
// - Sets the double byte padding for the current row
|
|
// Arguments:
|
|
// - fWrapWasForced - True if the row ran out of space for a double byte character and we padded out the row. False otherwise.
|
|
// Return Value:
|
|
// - <none>
|
|
void CharRow::SetDoubleBytePadded(const bool doubleBytePadded) noexcept
|
|
{
|
|
_doubleBytePadded = doubleBytePadded;
|
|
}
|
|
|
|
// Routine Description:
|
|
// - Gets the double byte padding status for the current row.
|
|
// Arguments:
|
|
// - <none>
|
|
// Return Value:
|
|
// - True if the row didn't have space for a double byte character and we were padded out the row. False otherwise.
|
|
bool CharRow::WasDoubleBytePadded() const noexcept
|
|
{
|
|
return _doubleBytePadded;
|
|
}
|
|
|
|
// Routine Description:
|
|
// - gets the size of the row, in glyph cells
|
|
// Arguments:
|
|
// - <none>
|
|
// Return Value:
|
|
// - the size of the row
|
|
size_t CharRow::size() const noexcept
|
|
{
|
|
return _data.size();
|
|
}
|
|
|
|
// Routine Description:
|
|
// - Sets all properties of the CharRowBase to default values
|
|
// Arguments:
|
|
// - sRowWidth - The width of the row.
|
|
// Return Value:
|
|
// - <none>
|
|
void CharRow::Reset()
|
|
{
|
|
for (auto& cell : _data)
|
|
{
|
|
cell.Reset();
|
|
}
|
|
|
|
_wrapForced = false;
|
|
_doubleBytePadded = false;
|
|
}
|
|
|
|
// Routine Description:
|
|
// - resizes the width of the CharRowBase
|
|
// Arguments:
|
|
// - newSize - the new width of the character and attributes rows
|
|
// Return Value:
|
|
// - S_OK on success, otherwise relevant error code
|
|
[[nodiscard]]
|
|
HRESULT CharRow::Resize(const size_t newSize) noexcept
|
|
{
|
|
try
|
|
{
|
|
const value_type insertVals;
|
|
_data.resize(newSize, insertVals);
|
|
}
|
|
CATCH_RETURN();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
typename CharRow::iterator CharRow::begin() noexcept
|
|
{
|
|
return _data.begin();
|
|
}
|
|
|
|
typename CharRow::const_iterator CharRow::cbegin() const noexcept
|
|
{
|
|
return _data.cbegin();
|
|
}
|
|
|
|
typename CharRow::iterator CharRow::end() noexcept
|
|
{
|
|
return _data.end();
|
|
}
|
|
|
|
typename CharRow::const_iterator CharRow::cend() const noexcept
|
|
{
|
|
return _data.cend();
|
|
}
|
|
|
|
// Routine Description:
|
|
// - Inspects the current internal string to find the left edge of it
|
|
// Arguments:
|
|
// - <none>
|
|
// Return Value:
|
|
// - The calculated left boundary of the internal string.
|
|
size_t CharRow::MeasureLeft() const
|
|
{
|
|
std::vector<value_type>::const_iterator it = _data.cbegin();
|
|
while (it != _data.cend() && it->IsSpace())
|
|
{
|
|
++it;
|
|
}
|
|
return it - _data.cbegin();
|
|
}
|
|
|
|
// Routine Description:
|
|
// - Inspects the current internal string to find the right edge of it
|
|
// Arguments:
|
|
// - <none>
|
|
// Return Value:
|
|
// - The calculated right boundary of the internal string.
|
|
size_t CharRow::MeasureRight() const noexcept
|
|
{
|
|
std::vector<value_type>::const_reverse_iterator it = _data.crbegin();
|
|
while (it != _data.crend() && it->IsSpace())
|
|
{
|
|
++it;
|
|
}
|
|
return _data.crend() - it;
|
|
}
|
|
|
|
void CharRow::ClearCell(const size_t column)
|
|
{
|
|
_data.at(column).Reset();
|
|
}
|
|
|
|
// Routine Description:
|
|
// - Tells you whether or not this row contains any valid text.
|
|
// Arguments:
|
|
// - <none>
|
|
// Return Value:
|
|
// - True if there is valid text in this row. False otherwise.
|
|
bool CharRow::ContainsText() const noexcept
|
|
{
|
|
for (const value_type& cell : _data)
|
|
{
|
|
if (!cell.IsSpace())
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Routine Description:
|
|
// - gets the attribute at the specified column
|
|
// Arguments:
|
|
// - column - the column to get the attribute for
|
|
// Return Value:
|
|
// - the attribute
|
|
// Note: will throw exception if column is out of bounds
|
|
const DbcsAttribute& CharRow::DbcsAttrAt(const size_t column) const
|
|
{
|
|
return _data.at(column).DbcsAttr();
|
|
}
|
|
|
|
// Routine Description:
|
|
// - gets the attribute at the specified column
|
|
// Arguments:
|
|
// - column - the column to get the attribute for
|
|
// Return Value:
|
|
// - the attribute
|
|
// Note: will throw exception if column is out of bounds
|
|
DbcsAttribute& CharRow::DbcsAttrAt(const size_t column)
|
|
{
|
|
return const_cast<DbcsAttribute&>(static_cast<const CharRow* const>(this)->DbcsAttrAt(column));
|
|
}
|
|
|
|
// Routine Description:
|
|
// - resets text data at column
|
|
// Arguments:
|
|
// - column - column index to clear text data from
|
|
// Return Value:
|
|
// - <none>
|
|
// Note: will throw exception if column is out of bounds
|
|
void CharRow::ClearGlyph(const size_t column)
|
|
{
|
|
_data.at(column).EraseChars();
|
|
}
|
|
|
|
// Routine Description:
|
|
// - returns text data at column as a const reference.
|
|
// Arguments:
|
|
// - column - column to get text data for
|
|
// Return Value:
|
|
// - text data at column
|
|
// - Note: will throw exception if column is out of bounds
|
|
const CharRow::reference CharRow::GlyphAt(const size_t column) const
|
|
{
|
|
THROW_HR_IF(E_INVALIDARG, column >= _data.size());
|
|
return { const_cast<CharRow&>(*this), column };
|
|
}
|
|
|
|
// Routine Description:
|
|
// - returns text data at column as a reference.
|
|
// Arguments:
|
|
// - column - column to get text data for
|
|
// Return Value:
|
|
// - text data at column
|
|
// - Note: will throw exception if column is out of bounds
|
|
CharRow::reference CharRow::GlyphAt(const size_t column)
|
|
{
|
|
THROW_HR_IF(E_INVALIDARG, column >= _data.size());
|
|
return { *this, column };
|
|
}
|
|
|
|
// Routine Description:
|
|
// - returns string containing text data exactly how it's stored internally, including doubling of
|
|
// leading/trailing cells.
|
|
// Arguments:
|
|
// - none
|
|
// Return Value:
|
|
// - text stored in char row
|
|
// - Note: will throw exception if out of memory
|
|
std::wstring CharRow::GetTextRaw() const
|
|
{
|
|
std::wstring wstr;
|
|
wstr.reserve(_data.size());
|
|
for (size_t i = 0; i < _data.size(); ++i)
|
|
{
|
|
auto glyph = GlyphAt(i);
|
|
for (auto it = glyph.begin(); it != glyph.end(); ++it)
|
|
{
|
|
wstr.push_back(*it);
|
|
}
|
|
}
|
|
return wstr;
|
|
}
|
|
|
|
std::wstring CharRow::GetText() const
|
|
{
|
|
std::wstring wstr;
|
|
wstr.reserve(_data.size());
|
|
|
|
for (size_t i = 0; i < _data.size(); ++i)
|
|
{
|
|
auto glyph = GlyphAt(i);
|
|
if (!DbcsAttrAt(i).IsTrailing())
|
|
{
|
|
for (auto it = glyph.begin(); it != glyph.end(); ++it)
|
|
{
|
|
wstr.push_back(*it);
|
|
}
|
|
}
|
|
}
|
|
return wstr;
|
|
}
|
|
|
|
UnicodeStorage& CharRow::GetUnicodeStorage()
|
|
{
|
|
return _pParent->GetUnicodeStorage();
|
|
}
|
|
|
|
const UnicodeStorage& CharRow::GetUnicodeStorage() const
|
|
{
|
|
return _pParent->GetUnicodeStorage();
|
|
}
|
|
|
|
// Routine Description:
|
|
// - calculates the key used by the given column of the char row to store glyph data in UnicodeStorage
|
|
// Arguments:
|
|
// - column - the column to generate the key for
|
|
// Return Value:
|
|
// - the COORD key for data access from UnicodeStorage for the column
|
|
COORD CharRow::GetStorageKey(const size_t column) const
|
|
{
|
|
return { gsl::narrow<SHORT>(column), _pParent->GetId() };
|
|
}
|
|
|
|
// Routine Description:
|
|
// - Updates the pointer to the parent row (which might change if we shuffle the rows around)
|
|
// Arguments:
|
|
// - pParent - Pointer to the parent row
|
|
void CharRow::UpdateParent(ROW* const pParent) noexcept
|
|
{
|
|
_pParent = FAIL_FAST_IF_NULL(pParent);
|
|
}
|