Merge pull request #2607 from microsoft/dev/miniksa/audit-a

Crank up static analysis audit
This commit is contained in:
Michael Niksa 2019-09-09 17:12:09 -07:00 committed by GitHub
commit 429af0e6fa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
75 changed files with 1475 additions and 1331 deletions

View file

@ -1,11 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="Console Rules" Description="These rules enforce static analysis on console code." ToolsVersion="15.0">
<Include Path="cppcorecheckrules.ruleset" Action="Default" />
<Include Path="cppcorecheckrules.ruleset" Action="Error" />
<Rules AnalyzerId="Microsoft.Analyzers.NativeCodeAnalysis" RuleNamespace="Microsoft.Rules.Native">
<Rule Id="C6001" Action="Error" />
<Rule Id="C6011" Action="Error" />
<Rules AnalyzerId="Microsoft.Analyzers.NativeCodeAnalysis" RuleNamespace="Microsoft.Rules.Native">
<Rule Id="C6001" Action="Error" />
<Rule Id="C6011" Action="Error" />
<!-- We can't do dynamic cast because RTTI is off. -->
<!-- RTTI is off because Windows OS policies believe RTTI has too much binary size impact for the value and is less portable than RTTI-off modules. -->
<Rule Id="C26466" Action="None" />
</Rules>
</RuleSet>

View file

@ -46,7 +46,7 @@ void ATTR_ROW::Resize(const size_t newWidth)
{
// Get the attribute that covers the final column of old width.
const auto runPos = FindAttrIndex(_cchRowWidth - 1, nullptr);
auto& run = _list[runPos];
auto& run = _list.at(runPos);
// Extend its length by the additional columns we're adding.
run.SetLength(run.GetLength() + newWidth - _cchRowWidth);
@ -60,7 +60,7 @@ void ATTR_ROW::Resize(const size_t newWidth)
// Get the attribute that covers the final column of the new width
size_t CountOfAttr = 0;
const auto runPos = FindAttrIndex(newWidth - 1, &CountOfAttr);
auto& run = _list[runPos];
auto& run = _list.at(runPos);
// CountOfAttr was given to us as "how many columns left from this point forward are covered by the returned run"
// So if the original run was B5 covering a 5 size OldWidth and we have a NewWidth of 3
@ -108,7 +108,7 @@ TextAttribute ATTR_ROW::GetAttrByColumn(const size_t column,
{
THROW_HR_IF(E_INVALIDARG, column >= _cchRowWidth);
const auto runPos = FindAttrIndex(column, pApplies);
return _list[runPos].GetAttributes();
return _list.at(runPos).GetAttributes();
}
// Routine Description:
@ -290,10 +290,10 @@ void ATTR_ROW::ReplaceAttrs(const TextAttribute& toBeReplacedAttr, const TextAtt
// two elements in our internal list.
else if (_list.size() == 2 && newAttrs.at(0).GetLength() == 1)
{
auto left = _list.begin();
const auto left = _list.begin();
if (iStart == left->GetLength() && NewAttr == left->GetAttributes())
{
auto right = left + 1;
const auto right = left + 1;
left->IncrementLength();
right->DecrementLength();

View file

@ -6,21 +6,21 @@
#include "AttrRowIterator.hpp"
#include "AttrRow.hpp"
AttrRowIterator AttrRowIterator::CreateEndIterator(const ATTR_ROW* const attrRow)
AttrRowIterator AttrRowIterator::CreateEndIterator(const ATTR_ROW* const attrRow) noexcept
{
AttrRowIterator it{ attrRow };
it._setToEnd();
return it;
}
AttrRowIterator::AttrRowIterator(const ATTR_ROW* const attrRow) :
AttrRowIterator::AttrRowIterator(const ATTR_ROW* const attrRow) noexcept :
_pAttrRow{ attrRow },
_run{ attrRow->_list.cbegin() },
_currentAttributeIndex{ 0 }
{
}
AttrRowIterator::operator bool() const noexcept
AttrRowIterator::operator bool() const
{
return _run < _pAttrRow->_list.cend();
}
@ -139,7 +139,7 @@ void AttrRowIterator::_decrement(size_t count)
// Routine Description:
// - sets fields on the iterator to describe the end() state of the ATTR_ROW
void AttrRowIterator::_setToEnd()
void AttrRowIterator::_setToEnd() noexcept
{
_run = _pAttrRow->_list.cend();
_currentAttributeIndex = 0;

View file

@ -29,11 +29,11 @@ public:
using pointer = TextAttribute*;
using reference = TextAttribute&;
static AttrRowIterator CreateEndIterator(const ATTR_ROW* const attrRow);
static AttrRowIterator CreateEndIterator(const ATTR_ROW* const attrRow) noexcept;
AttrRowIterator(const ATTR_ROW* const attrRow);
AttrRowIterator(const ATTR_ROW* const attrRow) noexcept;
operator bool() const noexcept;
operator bool() const;
bool operator==(const AttrRowIterator& it) const;
bool operator!=(const AttrRowIterator& it) const;
@ -57,5 +57,5 @@ private:
void _increment(size_t count);
void _decrement(size_t count);
void _setToEnd();
void _setToEnd() noexcept;
};

View file

@ -84,7 +84,7 @@ size_t CharRow::size() const noexcept
// - sRowWidth - The width of the row.
// Return Value:
// - <none>
void CharRow::Reset()
void CharRow::Reset() noexcept
{
for (auto& cell : _data)
{
@ -209,7 +209,7 @@ const DbcsAttribute& CharRow::DbcsAttrAt(const size_t column) const
// 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));
return _data.at(column).DbcsAttr();
}
// Routine Description:
@ -250,29 +250,6 @@ CharRow::reference CharRow::GlyphAt(const size_t column)
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;
@ -280,24 +257,24 @@ std::wstring CharRow::GetText() const
for (size_t i = 0; i < _data.size(); ++i)
{
auto glyph = GlyphAt(i);
const auto glyph = GlyphAt(i);
if (!DbcsAttrAt(i).IsTrailing())
{
for (auto it = glyph.begin(); it != glyph.end(); ++it)
for (const auto wch : glyph)
{
wstr.push_back(*it);
wstr.push_back(wch);
}
}
}
return wstr;
}
UnicodeStorage& CharRow::GetUnicodeStorage()
UnicodeStorage& CharRow::GetUnicodeStorage() noexcept
{
return _pParent->GetUnicodeStorage();
}
const UnicodeStorage& CharRow::GetUnicodeStorage() const
const UnicodeStorage& CharRow::GetUnicodeStorage() const noexcept
{
return _pParent->GetUnicodeStorage();
}
@ -308,7 +285,7 @@ const UnicodeStorage& CharRow::GetUnicodeStorage() const
// - 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
COORD CharRow::GetStorageKey(const size_t column) const noexcept
{
return { gsl::narrow<SHORT>(column), _pParent->GetId() };
}

View file

@ -53,7 +53,7 @@ public:
void SetDoubleBytePadded(const bool doubleBytePadded) noexcept;
bool WasDoubleBytePadded() const noexcept;
size_t size() const noexcept;
void Reset();
void Reset() noexcept;
[[nodiscard]] HRESULT Resize(const size_t newSize) noexcept;
size_t MeasureLeft() const;
size_t MeasureRight() const noexcept;
@ -64,9 +64,6 @@ public:
void ClearGlyph(const size_t column);
std::wstring GetText() const;
// other functions implemented at the template class level
std::wstring GetTextRaw() const;
// working with glyphs
const reference GlyphAt(const size_t column) const;
reference GlyphAt(const size_t column);
@ -78,9 +75,9 @@ public:
iterator end() noexcept;
const_iterator cend() const noexcept;
UnicodeStorage& GetUnicodeStorage();
const UnicodeStorage& GetUnicodeStorage() const;
COORD GetStorageKey(const size_t column) const;
UnicodeStorage& GetUnicodeStorage() noexcept;
const UnicodeStorage& GetUnicodeStorage() const noexcept;
COORD GetStorageKey(const size_t column) const noexcept;
void UpdateParent(ROW* const pParent) noexcept;

View file

@ -8,13 +8,13 @@
// default glyph value, used for reseting the character data portion of a cell
static constexpr wchar_t DefaultValue = UNICODE_SPACE;
CharRowCell::CharRowCell() :
CharRowCell::CharRowCell() noexcept :
_wch{ DefaultValue },
_attr{}
{
}
CharRowCell::CharRowCell(const wchar_t wch, const DbcsAttribute attr) :
CharRowCell::CharRowCell(const wchar_t wch, const DbcsAttribute attr) noexcept :
_wch{ wch },
_attr{ attr }
{
@ -22,7 +22,7 @@ CharRowCell::CharRowCell(const wchar_t wch, const DbcsAttribute attr) :
// Routine Description:
// - "erases" the glyph. really sets it back to the default "empty" value
void CharRowCell::EraseChars()
void CharRowCell::EraseChars() noexcept
{
if (_attr.IsGlyphStored())
{

View file

@ -27,10 +27,10 @@ Author(s):
class CharRowCell final
{
public:
CharRowCell();
CharRowCell(const wchar_t wch, const DbcsAttribute attr);
CharRowCell() noexcept;
CharRowCell(const wchar_t wch, const DbcsAttribute attr) noexcept;
void EraseChars();
void EraseChars() noexcept;
void Reset() noexcept;
bool IsSpace() const noexcept;

View file

@ -91,6 +91,9 @@ CharRowCellReference::const_iterator CharRowCellReference::begin() const
// - get read-only iterator to the end of the glyph data
// Return Value:
// - end iterator of the glyph data
#pragma warning(push)
#pragma warning(disable : 26481)
// TODO GH 2672: eliminate using pointers raw as begin/end markers in this class
CharRowCellReference::const_iterator CharRowCellReference::end() const
{
if (_cellData().DbcsAttr().IsGlyphStored())
@ -103,6 +106,7 @@ CharRowCellReference::const_iterator CharRowCellReference::end() const
return &_cellData().Char() + 1;
}
}
#pragma warning(pop)
bool operator==(const CharRowCellReference& ref, const std::vector<wchar_t>& glyph)
{

View file

@ -25,7 +25,7 @@ class CharRowCellReference final
public:
using const_iterator = const wchar_t*;
CharRowCellReference(CharRow& parent, const size_t index) :
CharRowCellReference(CharRow& parent, const size_t index) noexcept :
_parent{ parent },
_index{ index }
{

View file

@ -63,7 +63,7 @@ public:
return _glyphStored;
}
void SetGlyphStored(const bool stored)
void SetGlyphStored(const bool stored) noexcept
{
_glyphStored = stored;
}

View file

@ -11,7 +11,7 @@
static constexpr TextAttribute InvalidTextAttribute{ INVALID_COLOR, INVALID_COLOR };
OutputCell::OutputCell() :
OutputCell::OutputCell() noexcept :
_text{},
_dbcsAttribute{},
_textAttribute{ InvalidTextAttribute },
@ -111,7 +111,5 @@ void OutputCell::_setFromOutputCellView(const OutputCellView& cell)
_dbcsAttribute = cell.DbcsAttr();
_textAttribute = cell.TextAttr();
_behavior = cell.TextAttrBehavior();
const auto& view = cell.Chars();
_text = view;
_text = cell.Chars();
}

View file

@ -25,7 +25,7 @@ Author:
class InvalidCharInfoConversionException : public std::exception
{
const char* what() const noexcept
const char* what() const noexcept override
{
return "Cannot convert to CHAR_INFO without explicit TextAttribute";
}
@ -34,7 +34,7 @@ class InvalidCharInfoConversionException : public std::exception
class OutputCell final
{
public:
OutputCell();
OutputCell() noexcept;
OutputCell(const std::wstring_view charData,
const DbcsAttribute dbcsAttribute,

View file

@ -17,7 +17,7 @@ static constexpr TextAttribute InvalidTextAttribute{ INVALID_COLOR, INVALID_COLO
// Arguments:
// - wch - The character to use for filling
// - fillLimit - How many times to allow this value to be viewed/filled. Infinite if 0.
OutputCellIterator::OutputCellIterator(const wchar_t& wch, const size_t fillLimit) :
OutputCellIterator::OutputCellIterator(const wchar_t& wch, const size_t fillLimit) noexcept :
_mode(Mode::Fill),
_currentView(s_GenerateView(wch)),
_run(),
@ -33,7 +33,7 @@ OutputCellIterator::OutputCellIterator(const wchar_t& wch, const size_t fillLimi
// Arguments:
// - attr - The color attribute to use for filling
// - fillLimit - How many times to allow this value to be viewed/filled. Infinite if 0.
OutputCellIterator::OutputCellIterator(const TextAttribute& attr, const size_t fillLimit) :
OutputCellIterator::OutputCellIterator(const TextAttribute& attr, const size_t fillLimit) noexcept :
_mode(Mode::Fill),
_currentView(s_GenerateView(attr)),
_run(),
@ -50,7 +50,7 @@ OutputCellIterator::OutputCellIterator(const TextAttribute& attr, const size_t f
// - wch - The character to use for filling
// - attr - The color attribute to use for filling
// - fillLimit - How many times to allow this value to be viewed/filled. Infinite if 0.
OutputCellIterator::OutputCellIterator(const wchar_t& wch, const TextAttribute& attr, const size_t fillLimit) :
OutputCellIterator::OutputCellIterator(const wchar_t& wch, const TextAttribute& attr, const size_t fillLimit) noexcept :
_mode(Mode::Fill),
_currentView(s_GenerateView(wch, attr)),
_run(),
@ -66,7 +66,7 @@ OutputCellIterator::OutputCellIterator(const wchar_t& wch, const TextAttribute&
// Arguments:
// - charInfo - The legacy character and color data to use for fililng (uses Unicode portion of text data)
// - fillLimit - How many times to allow this value to be viewed/filled. Infinite if 0.
OutputCellIterator::OutputCellIterator(const CHAR_INFO& charInfo, const size_t fillLimit) :
OutputCellIterator::OutputCellIterator(const CHAR_INFO& charInfo, const size_t fillLimit) noexcept :
_mode(Mode::Fill),
_currentView(s_GenerateView(charInfo)),
_run(),
@ -116,7 +116,12 @@ OutputCellIterator::OutputCellIterator(const std::wstring_view utf16Text, const
// razzle cannot distinguish between a std::wstring_view and a std::basic_string_view<WORD>
// NOTE: This one internally casts to wchar_t because Razzle sees WORD and wchar_t as the same type
// despite that Visual Studio build can tell the difference.
OutputCellIterator::OutputCellIterator(const std::basic_string_view<WORD> legacyAttrs, const bool /*unused*/) :
#pragma warning(push)
#pragma warning(suppress : 26490)
// Suppresses reinterpret_cast. We're only doing this because Windows doesn't understand the type difference between wchar_t and DWORD.
// It is not worth trying to separate that out further or risking performance over this particular warning here.
// TODO GH 2673 - Investigate real wchar_t flag in Windows and resolve this audit issue
OutputCellIterator::OutputCellIterator(const std::basic_string_view<WORD> legacyAttrs, const bool /*unused*/) noexcept :
_mode(Mode::LegacyAttr),
_currentView(s_GenerateViewLegacyAttr(legacyAttrs.at(0))),
_run(std::wstring_view(reinterpret_cast<const wchar_t*>(legacyAttrs.data()), legacyAttrs.size())),
@ -126,12 +131,13 @@ OutputCellIterator::OutputCellIterator(const std::basic_string_view<WORD> legacy
_fillLimit(0)
{
}
#pragma warning(pop)
// Routine Description:
// - This is an iterator over legacy cell data. We will use the unicode text and the legacy color attribute.
// Arguments:
// - charInfos - Multiple cell with unicode text and legacy color data.
OutputCellIterator::OutputCellIterator(const std::basic_string_view<CHAR_INFO> charInfos) :
OutputCellIterator::OutputCellIterator(const std::basic_string_view<CHAR_INFO> charInfos) noexcept :
_mode(Mode::CharInfo),
_currentView(s_GenerateView(charInfos.at(0))),
_run(charInfos),
@ -315,7 +321,7 @@ OutputCellIterator OutputCellIterator::operator++(int)
// - Reference the view to fully-formed output cell data representing the underlying data source.
// Return Value:
// - Reference to the view
const OutputCellView& OutputCellIterator::operator*() const
const OutputCellView& OutputCellIterator::operator*() const noexcept
{
return _currentView;
}
@ -324,7 +330,7 @@ const OutputCellView& OutputCellIterator::operator*() const
// - Get pointer to the view to fully-formed output cell data representing the underlying data source.
// Return Value:
// - Pointer to the view
const OutputCellView* OutputCellIterator::operator->() const
const OutputCellView* OutputCellIterator::operator->() const noexcept
{
return &_currentView;
}
@ -338,7 +344,7 @@ const OutputCellView* OutputCellIterator::operator->() const
// - True if we just turned a lead half into a trailing half (and caller doesn't
// need to further update the view).
// - False if this wasn't applicable and the caller should update the view.
bool OutputCellIterator::_TryMoveTrailing()
bool OutputCellIterator::_TryMoveTrailing() noexcept
{
if (_currentView.DbcsAttr().IsLeading())
{
@ -421,7 +427,7 @@ OutputCellView OutputCellIterator::s_GenerateView(const std::wstring_view view,
// - wch - View representing a single UTF-16 character (that can be represented without surrogates)
// Return Value:
// - Object representing the view into this cell
OutputCellView OutputCellIterator::s_GenerateView(const wchar_t& wch)
OutputCellView OutputCellIterator::s_GenerateView(const wchar_t& wch) noexcept
{
const auto glyph = std::wstring_view(&wch, 1);
@ -443,7 +449,7 @@ OutputCellView OutputCellIterator::s_GenerateView(const wchar_t& wch)
// - attr - View representing a single color
// Return Value:
// - Object representing the view into this cell
OutputCellView OutputCellIterator::s_GenerateView(const TextAttribute& attr)
OutputCellView OutputCellIterator::s_GenerateView(const TextAttribute& attr) noexcept
{
return OutputCellView({}, {}, attr, TextAttributeBehavior::StoredOnly);
}
@ -458,7 +464,7 @@ OutputCellView OutputCellIterator::s_GenerateView(const TextAttribute& attr)
// - attr - View representing a single color
// Return Value:
// - Object representing the view into this cell
OutputCellView OutputCellIterator::s_GenerateView(const wchar_t& wch, const TextAttribute& attr)
OutputCellView OutputCellIterator::s_GenerateView(const wchar_t& wch, const TextAttribute& attr) noexcept
{
const auto glyph = std::wstring_view(&wch, 1);
@ -480,12 +486,12 @@ OutputCellView OutputCellIterator::s_GenerateView(const wchar_t& wch, const Text
// - legacyAttr - View representing a single legacy color
// Return Value:
// - Object representing the view into this cell
OutputCellView OutputCellIterator::s_GenerateViewLegacyAttr(const WORD& legacyAttr)
OutputCellView OutputCellIterator::s_GenerateViewLegacyAttr(const WORD& legacyAttr) noexcept
{
WORD cleanAttr = legacyAttr;
WI_ClearAllFlags(cleanAttr, COMMON_LVB_SBCSDBCS); // don't use legacy lead/trailing byte flags for colors
TextAttribute attr(cleanAttr);
const TextAttribute attr(cleanAttr);
return s_GenerateView(attr);
}
@ -498,7 +504,7 @@ OutputCellView OutputCellIterator::s_GenerateViewLegacyAttr(const WORD& legacyAt
// - charInfo - character and attribute pair representing a single cell
// Return Value:
// - Object representing the view into this cell
OutputCellView OutputCellIterator::s_GenerateView(const CHAR_INFO& charInfo)
OutputCellView OutputCellIterator::s_GenerateView(const CHAR_INFO& charInfo) noexcept
{
const auto glyph = std::wstring_view(&charInfo.Char.UnicodeChar, 1);

View file

@ -33,14 +33,14 @@ public:
using pointer = OutputCellView*;
using reference = OutputCellView&;
OutputCellIterator(const wchar_t& wch, const size_t fillLimit = 0);
OutputCellIterator(const TextAttribute& attr, const size_t fillLimit = 0);
OutputCellIterator(const wchar_t& wch, const TextAttribute& attr, const size_t fillLimit = 0);
OutputCellIterator(const CHAR_INFO& charInfo, const size_t fillLimit = 0);
OutputCellIterator(const wchar_t& wch, const size_t fillLimit = 0) noexcept;
OutputCellIterator(const TextAttribute& attr, const size_t fillLimit = 0) noexcept;
OutputCellIterator(const wchar_t& wch, const TextAttribute& attr, const size_t fillLimit = 0) noexcept;
OutputCellIterator(const CHAR_INFO& charInfo, const size_t fillLimit = 0) noexcept;
OutputCellIterator(const std::wstring_view utf16Text);
OutputCellIterator(const std::wstring_view utf16Text, const TextAttribute attribute);
OutputCellIterator(const std::basic_string_view<WORD> legacyAttributes, const bool unused);
OutputCellIterator(const std::basic_string_view<CHAR_INFO> charInfos);
OutputCellIterator(const std::basic_string_view<WORD> legacyAttributes, const bool unused) noexcept;
OutputCellIterator(const std::basic_string_view<CHAR_INFO> charInfos) noexcept;
OutputCellIterator(const std::basic_string_view<OutputCell> cells);
~OutputCellIterator() = default;
@ -55,8 +55,8 @@ public:
OutputCellIterator& operator++();
OutputCellIterator operator++(int);
const OutputCellView& operator*() const;
const OutputCellView* operator->() const;
const OutputCellView& operator*() const noexcept;
const OutputCellView* operator->() const noexcept;
private:
enum class Mode
@ -97,7 +97,7 @@ private:
TextAttribute _attr;
bool _TryMoveTrailing();
bool _TryMoveTrailing() noexcept;
static OutputCellView s_GenerateView(const std::wstring_view view);
@ -108,11 +108,11 @@ private:
const TextAttribute attr,
const TextAttributeBehavior behavior);
static OutputCellView s_GenerateView(const wchar_t& wch);
static OutputCellView s_GenerateViewLegacyAttr(const WORD& legacyAttr);
static OutputCellView s_GenerateView(const TextAttribute& attr);
static OutputCellView s_GenerateView(const wchar_t& wch, const TextAttribute& attr);
static OutputCellView s_GenerateView(const CHAR_INFO& charInfo);
static OutputCellView s_GenerateView(const wchar_t& wch) noexcept;
static OutputCellView s_GenerateViewLegacyAttr(const WORD& legacyAttr) noexcept;
static OutputCellView s_GenerateView(const TextAttribute& attr) noexcept;
static OutputCellView s_GenerateView(const wchar_t& wch, const TextAttribute& attr) noexcept;
static OutputCellView s_GenerateView(const CHAR_INFO& charInfo) noexcept;
static OutputCellView s_GenerateView(const OutputCell& cell);

View file

@ -7,7 +7,7 @@
// Routine Description:
// - Constucts an empty in-memory region for holding output buffer cell data.
OutputCellRect::OutputCellRect() :
OutputCellRect::OutputCellRect() noexcept :
_rows(0),
_cols(0)
{
@ -64,7 +64,7 @@ OutputCellIterator OutputCellRect::GetRowIter(const size_t row) const
// - Pointer to the location in the rectangle that represents the start of the requested row.
OutputCell* OutputCellRect::_FindRowOffset(const size_t row)
{
return (_storage.data() + (row * _cols));
return &_storage.at(row * _cols);
}
// Routine Description:
@ -76,7 +76,7 @@ OutputCell* OutputCellRect::_FindRowOffset(const size_t row)
// - Pointer to the location in the rectangle that represents the start of the requested row.
const OutputCell* OutputCellRect::_FindRowOffset(const size_t row) const
{
return (_storage.data() + (row * _cols));
return &_storage.at(row * _cols);
}
// Routine Description:

View file

@ -29,7 +29,7 @@ Revision History:
class OutputCellRect final
{
public:
OutputCellRect();
OutputCellRect() noexcept;
OutputCellRect(const size_t rows, const size_t cols);
gsl::span<OutputCell> GetRow(const size_t row);

View file

@ -15,7 +15,7 @@
OutputCellView::OutputCellView(const std::wstring_view view,
const DbcsAttribute dbcsAttr,
const TextAttribute textAttr,
const TextAttributeBehavior behavior) :
const TextAttributeBehavior behavior) noexcept :
_view(view),
_dbcsAttr(dbcsAttr),
_textAttr(textAttr),
@ -27,7 +27,9 @@ OutputCellView::OutputCellView(const std::wstring_view view,
// - Returns reference to view over text data
// Return Value:
// - Reference to UTF-16 character data
const std::wstring_view& OutputCellView::Chars() const noexcept
// 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;
}

View file

@ -28,7 +28,7 @@ public:
OutputCellView(const std::wstring_view view,
const DbcsAttribute dbcsAttr,
const TextAttribute textAttr,
const TextAttributeBehavior behavior);
const TextAttributeBehavior behavior) noexcept;
const std::wstring_view& Chars() const noexcept;
size_t Columns() const noexcept;

View file

@ -30,14 +30,14 @@ size_t ROW::size() const noexcept
return _rowWidth;
}
const CharRow& ROW::GetCharRow() const
const CharRow& ROW::GetCharRow() const noexcept
{
return _charRow;
}
CharRow& ROW::GetCharRow()
CharRow& ROW::GetCharRow() noexcept
{
return const_cast<CharRow&>(static_cast<const ROW* const>(this)->GetCharRow());
return _charRow;
}
const ATTR_ROW& ROW::GetAttrRow() const noexcept
@ -47,7 +47,7 @@ const ATTR_ROW& ROW::GetAttrRow() const noexcept
ATTR_ROW& ROW::GetAttrRow() noexcept
{
return const_cast<ATTR_ROW&>(static_cast<const ROW* const>(this)->GetAttrRow());
return _attrRow;
}
SHORT ROW::GetId() const noexcept
@ -132,12 +132,12 @@ RowCellIterator ROW::AsCellIter(const size_t startIndex, const size_t count) con
return RowCellIterator(*this, startIndex, count);
}
UnicodeStorage& ROW::GetUnicodeStorage()
UnicodeStorage& ROW::GetUnicodeStorage() noexcept
{
return _pParent->GetUnicodeStorage();
}
const UnicodeStorage& ROW::GetUnicodeStorage() const
const UnicodeStorage& ROW::GetUnicodeStorage() const noexcept
{
return _pParent->GetUnicodeStorage();
}

View file

@ -36,8 +36,8 @@ public:
size_t size() const noexcept;
const CharRow& GetCharRow() const;
CharRow& GetCharRow();
const CharRow& GetCharRow() const noexcept;
CharRow& GetCharRow() noexcept;
const ATTR_ROW& GetAttrRow() const noexcept;
ATTR_ROW& GetAttrRow() noexcept;
@ -54,8 +54,8 @@ public:
RowCellIterator AsCellIter(const size_t startIndex) const;
RowCellIterator AsCellIter(const size_t startIndex, const size_t count) const;
UnicodeStorage& GetUnicodeStorage();
const UnicodeStorage& GetUnicodeStorage() const;
UnicodeStorage& GetUnicodeStorage() noexcept;
const UnicodeStorage& GetUnicodeStorage() const noexcept;
OutputCellIterator WriteCells(OutputCellIterator it, const size_t index, const bool setWrap, std::optional<size_t> limitRight = std::nullopt);

View file

@ -37,38 +37,38 @@ bool RowCellIterator::operator!=(const RowCellIterator& it) const noexcept
return !(*this == it);
}
RowCellIterator& RowCellIterator::operator+=(const ptrdiff_t& movement)
RowCellIterator& RowCellIterator::operator+=(const ptrdiff_t& movement) noexcept
{
_pos += movement;
return (*this);
}
RowCellIterator& RowCellIterator::operator++()
RowCellIterator& RowCellIterator::operator++() noexcept
{
return this->operator+=(1);
}
RowCellIterator RowCellIterator::operator++(int)
RowCellIterator RowCellIterator::operator++(int) noexcept
{
auto temp(*this);
operator++();
return temp;
}
RowCellIterator RowCellIterator::operator+(const ptrdiff_t& movement)
RowCellIterator RowCellIterator::operator+(const ptrdiff_t& movement) noexcept
{
auto temp(*this);
temp += movement;
return temp;
}
const OutputCellView& RowCellIterator::operator*() const
const OutputCellView& RowCellIterator::operator*() const noexcept
{
return _view;
}
const OutputCellView* RowCellIterator::operator->() const
const OutputCellView* RowCellIterator::operator->() const noexcept
{
return &_view;
}

View file

@ -38,13 +38,13 @@ public:
bool operator==(const RowCellIterator& it) const noexcept;
bool operator!=(const RowCellIterator& it) const noexcept;
RowCellIterator& operator+=(const ptrdiff_t& movement);
RowCellIterator& operator++();
RowCellIterator operator++(int);
RowCellIterator operator+(const ptrdiff_t& movement);
RowCellIterator& operator+=(const ptrdiff_t& movement) noexcept;
RowCellIterator& operator++() noexcept;
RowCellIterator operator++(int) noexcept;
RowCellIterator operator+(const ptrdiff_t& movement) noexcept;
const OutputCellView& operator*() const;
const OutputCellView* operator->() const;
const OutputCellView& operator*() const noexcept;
const OutputCellView* operator->() const noexcept;
private:
const ROW& _row;

View file

@ -16,7 +16,7 @@ bool TextAttribute::IsLegacy() const noexcept
// - color that should be displayed as the foreground color
COLORREF TextAttribute::CalculateRgbForeground(std::basic_string_view<COLORREF> colorTable,
COLORREF defaultFgColor,
COLORREF defaultBgColor) const
COLORREF defaultBgColor) const noexcept
{
return _IsReverseVideo() ? _GetRgbBackground(colorTable, defaultBgColor) : _GetRgbForeground(colorTable, defaultFgColor);
}
@ -29,7 +29,7 @@ COLORREF TextAttribute::CalculateRgbForeground(std::basic_string_view<COLORREF>
// - color that should be displayed as the background color
COLORREF TextAttribute::CalculateRgbBackground(std::basic_string_view<COLORREF> colorTable,
COLORREF defaultFgColor,
COLORREF defaultBgColor) const
COLORREF defaultBgColor) const noexcept
{
return _IsReverseVideo() ? _GetRgbForeground(colorTable, defaultFgColor) : _GetRgbBackground(colorTable, defaultBgColor);
}
@ -42,7 +42,7 @@ COLORREF TextAttribute::CalculateRgbBackground(std::basic_string_view<COLORREF>
// Return Value:
// - color that is stored as the foreground color
COLORREF TextAttribute::_GetRgbForeground(std::basic_string_view<COLORREF> colorTable,
COLORREF defaultColor) const
COLORREF defaultColor) const noexcept
{
return _foreground.GetColor(colorTable, defaultColor, _isBold);
}
@ -55,7 +55,7 @@ COLORREF TextAttribute::_GetRgbForeground(std::basic_string_view<COLORREF> color
// Return Value:
// - color that is stored as the background color
COLORREF TextAttribute::_GetRgbBackground(std::basic_string_view<COLORREF> colorTable,
COLORREF defaultColor) const
COLORREF defaultColor) const noexcept
{
return _background.GetColor(colorTable, defaultColor, false);
}
@ -75,22 +75,22 @@ WORD TextAttribute::GetMetaAttributes() const noexcept
return wMeta;
}
void TextAttribute::SetForeground(const COLORREF rgbForeground)
void TextAttribute::SetForeground(const COLORREF rgbForeground) noexcept
{
_foreground = TextColor(rgbForeground);
}
void TextAttribute::SetBackground(const COLORREF rgbBackground)
void TextAttribute::SetBackground(const COLORREF rgbBackground) noexcept
{
_background = TextColor(rgbBackground);
}
void TextAttribute::SetFromLegacy(const WORD wLegacy) noexcept
{
_wAttrLegacy = static_cast<WORD>(wLegacy & META_ATTRS);
_wAttrLegacy = gsl::narrow_cast<WORD>(wLegacy & META_ATTRS);
WI_ClearAllFlags(_wAttrLegacy, COMMON_LVB_SBCSDBCS);
BYTE fgIndex = static_cast<BYTE>(wLegacy & FG_ATTRS);
BYTE bgIndex = static_cast<BYTE>(wLegacy & BG_ATTRS) >> 4;
const BYTE fgIndex = gsl::narrow_cast<BYTE>(wLegacy & FG_ATTRS);
const BYTE bgIndex = gsl::narrow_cast<BYTE>(wLegacy & BG_ATTRS) >> 4;
_foreground = TextColor(fgIndex);
_background = TextColor(bgIndex);
}
@ -98,16 +98,16 @@ void TextAttribute::SetFromLegacy(const WORD wLegacy) noexcept
void TextAttribute::SetLegacyAttributes(const WORD attrs,
const bool setForeground,
const bool setBackground,
const bool setMeta)
const bool setMeta) noexcept
{
if (setForeground)
{
BYTE fgIndex = (BYTE)(attrs & FG_ATTRS);
const BYTE fgIndex = gsl::narrow_cast<BYTE>(attrs & FG_ATTRS);
_foreground = TextColor(fgIndex);
}
if (setBackground)
{
BYTE bgIndex = (BYTE)(attrs & BG_ATTRS) >> 4;
const BYTE bgIndex = gsl::narrow_cast<BYTE>(attrs & BG_ATTRS) >> 4;
_background = TextColor(bgIndex);
}
if (setMeta)
@ -133,17 +133,17 @@ void TextAttribute::SetIndexedAttributes(const std::optional<const BYTE> foregro
{
if (foreground)
{
BYTE fgIndex = (*foreground) & 0xFF;
const BYTE fgIndex = (*foreground) & 0xFF;
_foreground = TextColor(fgIndex);
}
if (background)
{
BYTE bgIndex = (*background) & 0xFF;
const BYTE bgIndex = (*background) & 0xFF;
_background = TextColor(bgIndex);
}
}
void TextAttribute::SetColor(const COLORREF rgbColor, const bool fIsForeground)
void TextAttribute::SetColor(const COLORREF rgbColor, const bool fIsForeground) noexcept
{
if (fIsForeground)
{

View file

@ -39,9 +39,9 @@ public:
}
constexpr TextAttribute(const WORD wLegacyAttr) noexcept :
_wAttrLegacy{ static_cast<WORD>(wLegacyAttr & META_ATTRS) },
_foreground{ static_cast<BYTE>(wLegacyAttr & FG_ATTRS) },
_background{ static_cast<BYTE>((wLegacyAttr & BG_ATTRS) >> 4) },
_wAttrLegacy{ gsl::narrow_cast<WORD>(wLegacyAttr & META_ATTRS) },
_foreground{ gsl::narrow_cast<BYTE>(wLegacyAttr & FG_ATTRS) },
_background{ gsl::narrow_cast<BYTE>((wLegacyAttr & BG_ATTRS) >> 4) },
_isBold{ false }
{
// If we're given lead/trailing byte information with the legacy color, strip it.
@ -59,9 +59,9 @@ public:
constexpr WORD GetLegacyAttributes() const noexcept
{
BYTE fg = (_foreground.GetIndex() & FG_ATTRS);
BYTE bg = (_background.GetIndex() << 4) & BG_ATTRS;
WORD meta = (_wAttrLegacy & META_ATTRS);
const BYTE fg = (_foreground.GetIndex() & FG_ATTRS);
const BYTE bg = (_background.GetIndex() << 4) & BG_ATTRS;
const WORD meta = (_wAttrLegacy & META_ATTRS);
return (fg | bg | meta) | (_isBold ? FOREGROUND_INTENSITY : 0);
}
@ -80,20 +80,20 @@ public:
constexpr WORD GetLegacyAttributes(const BYTE defaultFgIndex,
const BYTE defaultBgIndex) const noexcept
{
BYTE fgIndex = _foreground.IsLegacy() ? _foreground.GetIndex() : defaultFgIndex;
BYTE bgIndex = _background.IsLegacy() ? _background.GetIndex() : defaultBgIndex;
BYTE fg = (fgIndex & FG_ATTRS);
BYTE bg = (bgIndex << 4) & BG_ATTRS;
WORD meta = (_wAttrLegacy & META_ATTRS);
const BYTE fgIndex = _foreground.IsLegacy() ? _foreground.GetIndex() : defaultFgIndex;
const BYTE bgIndex = _background.IsLegacy() ? _background.GetIndex() : defaultBgIndex;
const BYTE fg = (fgIndex & FG_ATTRS);
const BYTE bg = (bgIndex << 4) & BG_ATTRS;
const WORD meta = (_wAttrLegacy & META_ATTRS);
return (fg | bg | meta) | (_isBold ? FOREGROUND_INTENSITY : 0);
}
COLORREF CalculateRgbForeground(std::basic_string_view<COLORREF> colorTable,
COLORREF defaultFgColor,
COLORREF defaultBgColor) const;
COLORREF defaultBgColor) const noexcept;
COLORREF CalculateRgbBackground(std::basic_string_view<COLORREF> colorTable,
COLORREF defaultFgColor,
COLORREF defaultBgColor) const;
COLORREF defaultBgColor) const noexcept;
bool IsLeadingByte() const noexcept;
bool IsTrailingByte() const noexcept;
@ -110,7 +110,7 @@ public:
void SetLegacyAttributes(const WORD attrs,
const bool setForeground,
const bool setBackground,
const bool setMeta);
const bool setMeta) noexcept;
void SetIndexedAttributes(const std::optional<const BYTE> foreground,
const std::optional<const BYTE> background) noexcept;
@ -133,9 +133,9 @@ public:
bool IsLegacy() const noexcept;
bool IsBold() const noexcept;
void SetForeground(const COLORREF rgbForeground);
void SetBackground(const COLORREF rgbBackground);
void SetColor(const COLORREF rgbColor, const bool fIsForeground);
void SetForeground(const COLORREF rgbForeground) noexcept;
void SetBackground(const COLORREF rgbBackground) noexcept;
void SetColor(const COLORREF rgbColor, const bool fIsForeground) noexcept;
void SetDefaultForeground() noexcept;
void SetDefaultBackground() noexcept;
@ -150,9 +150,9 @@ public:
private:
COLORREF _GetRgbForeground(std::basic_string_view<COLORREF> colorTable,
COLORREF defaultColor) const;
COLORREF defaultColor) const noexcept;
COLORREF _GetRgbBackground(std::basic_string_view<COLORREF> colorTable,
COLORREF defaultColor) const;
COLORREF defaultColor) const noexcept;
bool _IsReverseVideo() const noexcept;
void _SetBoldness(const bool isBold) noexcept;

View file

@ -11,7 +11,7 @@
// - rgbColor: the COLORREF containing the color information for this TextColor
// Return Value:
// - <none>
void TextColor::SetColor(const COLORREF rgbColor)
void TextColor::SetColor(const COLORREF rgbColor) noexcept
{
_meta = ColorType::IsRgb;
_red = GetRValue(rgbColor);
@ -25,7 +25,7 @@ void TextColor::SetColor(const COLORREF rgbColor)
// - index: the index of the colortable we should use for this TextColor.
// Return Value:
// - <none>
void TextColor::SetIndex(const BYTE index)
void TextColor::SetIndex(const BYTE index) noexcept
{
_meta = ColorType::IsIndex;
_index = index;
@ -38,7 +38,7 @@ void TextColor::SetIndex(const BYTE index)
// - <none>
// Return Value:
// - <none>
void TextColor::SetDefault()
void TextColor::SetDefault() noexcept
{
_meta = ColorType::IsDefault;
}
@ -63,7 +63,7 @@ void TextColor::SetDefault()
// - a COLORREF containing the real value of this TextColor.
COLORREF TextColor::GetColor(std::basic_string_view<COLORREF> colorTable,
const COLORREF defaultColor,
bool brighten) const
bool brighten) const noexcept
{
if (IsDefault())
{
@ -81,9 +81,9 @@ COLORREF TextColor::GetColor(std::basic_string_view<COLORREF> colorTable,
// If we find a match, return instead the bright version of this color
for (size_t i = 0; i < 8; i++)
{
if (colorTable[i] == defaultColor)
if (colorTable.at(i) == defaultColor)
{
return colorTable[i + 8];
return colorTable.at(i + 8);
}
}
}
@ -102,12 +102,12 @@ COLORREF TextColor::GetColor(std::basic_string_view<COLORREF> colorTable,
if (brighten && _index < 8)
{
FAIL_FAST_IF(colorTable.size() < 16);
FAIL_FAST_IF((size_t)(_index + 8) > (size_t)(colorTable.size()));
return colorTable[_index + 8];
FAIL_FAST_IF(gsl::narrow_cast<size_t>(_index) + 8 > colorTable.size());
return colorTable.at(gsl::narrow_cast<size_t>(_index) + 8);
}
else
{
return colorTable[_index];
return colorTable.at(_index);
}
}
}
@ -119,7 +119,7 @@ COLORREF TextColor::GetColor(std::basic_string_view<COLORREF> colorTable,
// - <none>
// Return Value:
// - a COLORREF containing our stored value
COLORREF TextColor::_GetRGB() const
COLORREF TextColor::_GetRGB() const noexcept
{
return RGB(_red, _green, _blue);
}

View file

@ -91,13 +91,13 @@ public:
return _meta == ColorType::IsRgb;
}
void SetColor(const COLORREF rgbColor);
void SetIndex(const BYTE index);
void SetDefault();
void SetColor(const COLORREF rgbColor) noexcept;
void SetIndex(const BYTE index) noexcept;
void SetDefault() noexcept;
COLORREF GetColor(std::basic_string_view<COLORREF> colorTable,
const COLORREF defaultColor,
const bool brighten) const;
const bool brighten) const noexcept;
constexpr BYTE GetIndex() const noexcept
{
@ -113,7 +113,7 @@ private:
BYTE _green;
BYTE _blue;
COLORREF _GetRGB() const;
COLORREF _GetRGB() const noexcept;
#ifdef UNIT_TESTING
friend class TextBufferTests;

View file

@ -4,7 +4,7 @@
#include "precomp.h"
#include "UnicodeStorage.hpp"
UnicodeStorage::UnicodeStorage() :
UnicodeStorage::UnicodeStorage() noexcept :
_map{}
{
}
@ -35,7 +35,7 @@ void UnicodeStorage::StoreGlyph(const key_type key, const mapped_type& glyph)
// - erases key and its associated data from the storage
// Arguments:
// - key - the key to remove
void UnicodeStorage::Erase(const key_type key) noexcept
void UnicodeStorage::Erase(const key_type key)
{
_map.erase(key);
}

View file

@ -47,13 +47,13 @@ public:
using key_type = typename COORD;
using mapped_type = typename std::vector<wchar_t>;
UnicodeStorage();
UnicodeStorage() noexcept;
const mapped_type& GetText(const key_type key) const;
void StoreGlyph(const key_type key, const mapped_type& glyph);
void Erase(const key_type key) noexcept;
void Erase(const key_type key);
void Remap(const std::map<SHORT, SHORT>& rowMap, const std::optional<SHORT> width);

View file

@ -11,7 +11,7 @@
// - Constructor to set default properties for Cursor
// Arguments:
// - ulSize - The height of the cursor within this buffer
Cursor::Cursor(const ULONG ulSize, TextBuffer& parentBuffer) :
Cursor::Cursor(const ULONG ulSize, TextBuffer& parentBuffer) noexcept :
_parentBuffer{ parentBuffer },
_cPosition{ 0 },
_fHasMoved(false),
@ -87,36 +87,36 @@ ULONG Cursor::GetSize() const noexcept
return _ulSize;
}
void Cursor::SetHasMoved(const bool fHasMoved)
void Cursor::SetHasMoved(const bool fHasMoved) noexcept
{
_fHasMoved = fHasMoved;
}
void Cursor::SetIsVisible(const bool fIsVisible)
void Cursor::SetIsVisible(const bool fIsVisible) noexcept
{
_fIsVisible = fIsVisible;
_RedrawCursor();
}
void Cursor::SetIsOn(const bool fIsOn)
void Cursor::SetIsOn(const bool fIsOn) noexcept
{
_fIsOn = fIsOn;
_RedrawCursorAlways();
}
void Cursor::SetBlinkingAllowed(const bool fBlinkingAllowed)
void Cursor::SetBlinkingAllowed(const bool fBlinkingAllowed) noexcept
{
_fBlinkingAllowed = fBlinkingAllowed;
_RedrawCursorAlways();
}
void Cursor::SetIsDouble(const bool fIsDouble)
void Cursor::SetIsDouble(const bool fIsDouble) noexcept
{
_fIsDouble = fIsDouble;
_RedrawCursor();
}
void Cursor::SetIsConversionArea(const bool fIsConversionArea)
void Cursor::SetIsConversionArea(const bool fIsConversionArea) noexcept
{
// Functionally the same as "Hide cursor"
// Never called with TRUE, it's only used in the creation of a
@ -125,19 +125,19 @@ void Cursor::SetIsConversionArea(const bool fIsConversionArea)
_RedrawCursorAlways();
}
void Cursor::SetIsPopupShown(const bool fIsPopupShown)
void Cursor::SetIsPopupShown(const bool fIsPopupShown) noexcept
{
// Functionally the same as "Hide cursor"
_fIsPopupShown = fIsPopupShown;
_RedrawCursorAlways();
}
void Cursor::SetDelay(const bool fDelay)
void Cursor::SetDelay(const bool fDelay) noexcept
{
_fDelay = fDelay;
}
void Cursor::SetSize(const ULONG ulSize)
void Cursor::SetSize(const ULONG ulSize) noexcept
{
_ulSize = ulSize;
_RedrawCursor();
@ -195,7 +195,7 @@ void Cursor::_RedrawCursorAlways() noexcept
CATCH_LOG();
}
void Cursor::SetPosition(const COORD cPosition)
void Cursor::SetPosition(const COORD cPosition) noexcept
{
_RedrawCursor();
_cPosition.X = cPosition.X;
@ -204,50 +204,50 @@ void Cursor::SetPosition(const COORD cPosition)
ResetDelayEOLWrap();
}
void Cursor::SetXPosition(const int NewX)
void Cursor::SetXPosition(const int NewX) noexcept
{
_RedrawCursor();
_cPosition.X = (SHORT)NewX;
_cPosition.X = gsl::narrow<SHORT>(NewX);
_RedrawCursor();
ResetDelayEOLWrap();
}
void Cursor::SetYPosition(const int NewY)
void Cursor::SetYPosition(const int NewY) noexcept
{
_RedrawCursor();
_cPosition.Y = (SHORT)NewY;
_cPosition.Y = gsl::narrow<SHORT>(NewY);
_RedrawCursor();
ResetDelayEOLWrap();
}
void Cursor::IncrementXPosition(const int DeltaX)
void Cursor::IncrementXPosition(const int DeltaX) noexcept
{
_RedrawCursor();
_cPosition.X += (SHORT)DeltaX;
_cPosition.X += gsl::narrow<SHORT>(DeltaX);
_RedrawCursor();
ResetDelayEOLWrap();
}
void Cursor::IncrementYPosition(const int DeltaY)
void Cursor::IncrementYPosition(const int DeltaY) noexcept
{
_RedrawCursor();
_cPosition.Y += (SHORT)DeltaY;
_cPosition.Y += gsl::narrow<SHORT>(DeltaY);
_RedrawCursor();
ResetDelayEOLWrap();
}
void Cursor::DecrementXPosition(const int DeltaX)
void Cursor::DecrementXPosition(const int DeltaX) noexcept
{
_RedrawCursor();
_cPosition.X -= (SHORT)DeltaX;
_cPosition.X -= gsl::narrow<SHORT>(DeltaX);
_RedrawCursor();
ResetDelayEOLWrap();
}
void Cursor::DecrementYPosition(const int DeltaY)
void Cursor::DecrementYPosition(const int DeltaY) noexcept
{
_RedrawCursor();
_cPosition.Y -= (SHORT)DeltaY;
_cPosition.Y -= gsl::narrow<SHORT>(DeltaY);
_RedrawCursor();
ResetDelayEOLWrap();
}
@ -262,7 +262,7 @@ void Cursor::DecrementYPosition(const int DeltaY)
// - OtherCursor - The cursor to copy properties from
// Return Value:
// - <none>
void Cursor::CopyProperties(const Cursor& OtherCursor)
void Cursor::CopyProperties(const Cursor& OtherCursor) noexcept
{
// We shouldn't copy the position as it will be already rearranged by the resize operation.
//_cPosition = pOtherCursor->_cPosition;
@ -288,34 +288,34 @@ void Cursor::CopyProperties(const Cursor& OtherCursor)
_color = OtherCursor._color;
}
void Cursor::DelayEOLWrap(const COORD coordDelayedAt)
void Cursor::DelayEOLWrap(const COORD coordDelayedAt) noexcept
{
_coordDelayedAt = coordDelayedAt;
_fDelayedEolWrap = true;
}
void Cursor::ResetDelayEOLWrap()
void Cursor::ResetDelayEOLWrap() noexcept
{
_coordDelayedAt = { 0 };
_fDelayedEolWrap = false;
}
COORD Cursor::GetDelayedAtPosition() const
COORD Cursor::GetDelayedAtPosition() const noexcept
{
return _coordDelayedAt;
}
bool Cursor::IsDelayedEOLWrap() const
bool Cursor::IsDelayedEOLWrap() const noexcept
{
return _fDelayedEolWrap;
}
void Cursor::StartDeferDrawing()
void Cursor::StartDeferDrawing() noexcept
{
_fDeferCursorRedraw = true;
}
void Cursor::EndDeferDrawing()
void Cursor::EndDeferDrawing() noexcept
{
if (_fHaveDeferredCursorRedraw)
{
@ -325,27 +325,27 @@ void Cursor::EndDeferDrawing()
_fDeferCursorRedraw = FALSE;
}
const CursorType Cursor::GetType() const
const CursorType Cursor::GetType() const noexcept
{
return _cursorType;
}
const bool Cursor::IsUsingColor() const
const bool Cursor::IsUsingColor() const noexcept
{
return GetColor() != INVALID_COLOR;
}
const COLORREF Cursor::GetColor() const
const COLORREF Cursor::GetColor() const noexcept
{
return _color;
}
void Cursor::SetColor(const unsigned int color)
void Cursor::SetColor(const unsigned int color) noexcept
{
_color = (COLORREF)color;
_color = gsl::narrow_cast<COLORREF>(color);
}
void Cursor::SetType(const CursorType type)
void Cursor::SetType(const CursorType type) noexcept
{
_cursorType = type;
}

View file

@ -28,7 +28,7 @@ class Cursor final
public:
static const unsigned int s_InvertCursorColor = INVALID_COLOR;
Cursor(const ULONG ulSize, TextBuffer& parentBuffer);
Cursor(const ULONG ulSize, TextBuffer& parentBuffer) noexcept;
~Cursor();
@ -50,41 +50,41 @@ public:
ULONG GetSize() const noexcept;
COORD GetPosition() const noexcept;
const CursorType GetType() const;
const bool IsUsingColor() const;
const COLORREF GetColor() const;
const CursorType GetType() const noexcept;
const bool IsUsingColor() const noexcept;
const COLORREF GetColor() const noexcept;
void StartDeferDrawing();
void EndDeferDrawing();
void StartDeferDrawing() noexcept;
void EndDeferDrawing() noexcept;
void SetHasMoved(const bool fHasMoved);
void SetIsVisible(const bool fIsVisible);
void SetIsOn(const bool fIsOn);
void SetBlinkingAllowed(const bool fIsOn);
void SetIsDouble(const bool fIsDouble);
void SetIsConversionArea(const bool fIsConversionArea);
void SetIsPopupShown(const bool fIsPopupShown);
void SetDelay(const bool fDelay);
void SetSize(const ULONG ulSize);
void SetHasMoved(const bool fHasMoved) noexcept;
void SetIsVisible(const bool fIsVisible) noexcept;
void SetIsOn(const bool fIsOn) noexcept;
void SetBlinkingAllowed(const bool fIsOn) noexcept;
void SetIsDouble(const bool fIsDouble) noexcept;
void SetIsConversionArea(const bool fIsConversionArea) noexcept;
void SetIsPopupShown(const bool fIsPopupShown) noexcept;
void SetDelay(const bool fDelay) noexcept;
void SetSize(const ULONG ulSize) noexcept;
void SetStyle(const ULONG ulSize, const COLORREF color, const CursorType type) noexcept;
void SetPosition(const COORD cPosition);
void SetXPosition(const int NewX);
void SetYPosition(const int NewY);
void IncrementXPosition(const int DeltaX);
void IncrementYPosition(const int DeltaY);
void DecrementXPosition(const int DeltaX);
void DecrementYPosition(const int DeltaY);
void SetPosition(const COORD cPosition) noexcept;
void SetXPosition(const int NewX) noexcept;
void SetYPosition(const int NewY) noexcept;
void IncrementXPosition(const int DeltaX) noexcept;
void IncrementYPosition(const int DeltaY) noexcept;
void DecrementXPosition(const int DeltaX) noexcept;
void DecrementYPosition(const int DeltaY) noexcept;
void CopyProperties(const Cursor& OtherCursor);
void CopyProperties(const Cursor& OtherCursor) noexcept;
void DelayEOLWrap(const COORD coordDelayedAt);
void ResetDelayEOLWrap();
COORD GetDelayedAtPosition() const;
bool IsDelayedEOLWrap() const;
void DelayEOLWrap(const COORD coordDelayedAt) noexcept;
void ResetDelayEOLWrap() noexcept;
COORD GetDelayedAtPosition() const noexcept;
bool IsDelayedEOLWrap() const noexcept;
void SetColor(const unsigned int color);
void SetType(const CursorType type);
void SetColor(const unsigned int color) noexcept;
void SetType(const CursorType type) noexcept;
private:
TextBuffer& _parentBuffer;

View file

@ -49,7 +49,7 @@ TextBuffer::TextBuffer(const COORD screenBufferSize,
// - OtherBuffer - The text buffer to copy properties from
// Return Value:
// - <none>
void TextBuffer::CopyProperties(const TextBuffer& OtherBuffer)
void TextBuffer::CopyProperties(const TextBuffer& OtherBuffer) noexcept
{
GetCursor().CopyProperties(OtherBuffer.GetCursor());
}
@ -60,9 +60,9 @@ void TextBuffer::CopyProperties(const TextBuffer& OtherBuffer)
// - <none>
// Return Value:
// - Total number of rows in the buffer
UINT TextBuffer::TotalRowCount() const
UINT TextBuffer::TotalRowCount() const noexcept
{
return static_cast<UINT>(_storage.size());
return gsl::narrow<UINT>(_storage.size());
}
// Routine Description:
@ -78,7 +78,7 @@ const ROW& TextBuffer::GetRowByOffset(const size_t index) const
// Rows are stored circularly, so the index you ask for is offset by the start position and mod the total of rows.
const size_t offsetIndex = (_firstRow + index) % totalRows;
return _storage[offsetIndex];
return _storage.at(offsetIndex);
}
// Routine Description:
@ -90,7 +90,11 @@ const ROW& TextBuffer::GetRowByOffset(const size_t index) const
// - reference to the requested row. Asserts if out of bounds.
ROW& TextBuffer::GetRowByOffset(const size_t index)
{
return const_cast<ROW&>(static_cast<const TextBuffer*>(this)->GetRowByOffset(index));
const size_t totalRows = TotalRowCount();
// Rows are stored circularly, so the index you ask for is offset by the start position and mod the total of rows.
const size_t offsetIndex = (_firstRow + index) % totalRows;
return _storage.at(offsetIndex);
}
// Routine Description:
@ -542,7 +546,7 @@ bool TextBuffer::IncrementCircularBuffer()
_renderTarget.TriggerCircling();
// First, clean out the old "first row" as it will become the "last row" of the buffer after the circle is performed.
bool fSuccess = _storage.at(_firstRow).Reset(_currentAttributes);
const bool fSuccess = _storage.at(_firstRow).Reset(_currentAttributes);
if (fSuccess)
{
// Now proceed to increment.
@ -584,9 +588,9 @@ COORD TextBuffer::GetLastNonSpaceCharacter(const Microsoft::Console::Types::View
// Search the given viewport by starting at the bottom.
coordEndOfText.Y = viewport.BottomInclusive();
const ROW* pCurrRow = &GetRowByOffset(coordEndOfText.Y);
const auto& currRow = GetRowByOffset(coordEndOfText.Y);
// The X position of the end of the valid text is the Right draw boundary (which is one beyond the final valid character)
coordEndOfText.X = static_cast<short>(pCurrRow->GetCharRow().MeasureRight()) - 1;
coordEndOfText.X = gsl::narrow<short>(currRow.GetCharRow().MeasureRight()) - 1;
// If the X coordinate turns out to be -1, the row was empty, we need to search backwards for the real end of text.
const auto viewportTop = viewport.Top();
@ -594,10 +598,10 @@ COORD TextBuffer::GetLastNonSpaceCharacter(const Microsoft::Console::Types::View
while (fDoBackUp)
{
coordEndOfText.Y--;
pCurrRow = &GetRowByOffset(coordEndOfText.Y);
const auto& backupRow = GetRowByOffset(coordEndOfText.Y);
// We need to back up to the previous row if this line is empty, AND there are more rows
coordEndOfText.X = static_cast<short>(pCurrRow->GetCharRow().MeasureRight()) - 1;
coordEndOfText.X = gsl::narrow<short>(backupRow.GetCharRow().MeasureRight()) - 1;
fDoBackUp = (coordEndOfText.X < 0 && coordEndOfText.Y > viewportTop);
}
@ -640,7 +644,7 @@ COORD TextBuffer::_GetPreviousFromCursor() const
return coordPosition;
}
const SHORT TextBuffer::GetFirstRowIndex() const
const SHORT TextBuffer::GetFirstRowIndex() const noexcept
{
return _firstRow;
}
@ -649,7 +653,7 @@ const Viewport TextBuffer::GetSize() const
return Viewport::FromDimensions({ 0, 0 }, { gsl::narrow<SHORT>(_storage.at(0).size()), gsl::narrow<SHORT>(_storage.size()) });
}
void TextBuffer::_SetFirstRowIndex(const SHORT FirstRowIndex)
void TextBuffer::_SetFirstRowIndex(const SHORT FirstRowIndex) noexcept
{
_firstRow = FirstRowIndex;
}
@ -755,12 +759,12 @@ void TextBuffer::ScrollRows(const SHORT firstRow, const SHORT size, const SHORT
_RefreshRowIDs(std::nullopt);
}
Cursor& TextBuffer::GetCursor()
Cursor& TextBuffer::GetCursor() noexcept
{
return _cursor;
}
const Cursor& TextBuffer::GetCursor() const
const Cursor& TextBuffer::GetCursor() const noexcept
{
return _cursor;
}
@ -795,7 +799,7 @@ void TextBuffer::Reset()
// - newSize - new size of screen.
// Return Value:
// - Success if successful. Invalid parameter if screen buffer size is unexpected. No memory if allocation failed.
[[nodiscard]] NTSTATUS TextBuffer::ResizeTraditional(const COORD newSize) noexcept
[[nodiscard]] NTSTATUS TextBuffer::ResizeTraditional(const COORD newSize)
{
RETURN_HR_IF(E_INVALIDARG, newSize.X < 0 || newSize.Y < 0);
@ -812,7 +816,7 @@ void TextBuffer::Reset()
// rotate rows until the top row is at index 0
try
{
const ROW& newTopRow = _storage[TopRowIndex];
const ROW& newTopRow = _storage.at(TopRowIndex);
while (&newTopRow != &_storage.front())
{
_storage.push_back(std::move(_storage.front()));
@ -843,12 +847,12 @@ void TextBuffer::Reset()
return S_OK;
}
const UnicodeStorage& TextBuffer::GetUnicodeStorage() const
const UnicodeStorage& TextBuffer::GetUnicodeStorage() const noexcept
{
return _unicodeStorage;
}
UnicodeStorage& TextBuffer::GetUnicodeStorage()
UnicodeStorage& TextBuffer::GetUnicodeStorage() noexcept
{
return _unicodeStorage;
}
@ -923,7 +927,7 @@ ROW& TextBuffer::_GetPrevRowNoWrap(const ROW& Row)
}
THROW_HR_IF(E_FAIL, Row.GetId() == _firstRow);
return _storage[prevRowIndex];
return _storage.at(prevRowIndex);
}
// Method Description:
@ -932,7 +936,7 @@ ROW& TextBuffer::_GetPrevRowNoWrap(const ROW& Row)
// - <none>
// Return Value:
// - This buffer's current render target.
Microsoft::Console::Render::IRenderTarget& TextBuffer::GetRenderTarget()
Microsoft::Console::Render::IRenderTarget& TextBuffer::GetRenderTarget() noexcept
{
return _renderTarget;
}
@ -977,9 +981,9 @@ const TextBuffer::TextAndColor TextBuffer::GetTextForClipboard(const bool lineSe
std::vector<COLORREF> selectionBkAttr;
// preallocate to avoid reallocs
selectionText.reserve(highlight.Width() + 2); // + 2 for \r\n if we munged it
selectionFgAttr.reserve(highlight.Width() + 2);
selectionBkAttr.reserve(highlight.Width() + 2);
selectionText.reserve(gsl::narrow<size_t>(highlight.Width()) + 2); // + 2 for \r\n if we munged it
selectionFgAttr.reserve(gsl::narrow<size_t>(highlight.Width()) + 2);
selectionBkAttr.reserve(gsl::narrow<size_t>(highlight.Width()) + 2);
// copy char data into the string buffer, skipping trailing bytes
while (it)
@ -998,6 +1002,8 @@ const TextBuffer::TextAndColor TextBuffer::GetTextForClipboard(const bool lineSe
selectionBkAttr.push_back(CellBkAttr);
}
}
#pragma warning(suppress : 26444)
// TODO GH 2675: figure out why there's custom construction/destruction happening here
it++;
}
@ -1059,6 +1065,10 @@ std::string TextBuffer::GenHTML(const TextAndColor& rows, const int fontHeightPo
{
try
{
// TODO: GH 602 the font name needs to be passed and stored around as an actual bounded type, not an implicit bounds on LF_FACESIZE
const auto faceLength = wcsnlen_s(fontFaceName, LF_FACESIZE);
const std::wstring_view faceNameView{ fontFaceName, faceLength };
std::ostringstream htmlBuilder;
// First we have to add some standard
@ -1084,12 +1094,9 @@ std::string TextBuffer::GenHTML(const TextAndColor& rows, const int fontHeightPo
htmlBuilder << ";";
htmlBuilder << "font-family:";
if (fontFaceName[0] != '\0')
{
htmlBuilder << "'";
htmlBuilder << ConvertToA(CP_UTF8, fontFaceName);
htmlBuilder << "',";
}
htmlBuilder << "'";
htmlBuilder << ConvertToA(CP_UTF8, faceNameView);
htmlBuilder << "',";
// even with different font, add monospace as fallback
htmlBuilder << "monospace;";
@ -1109,7 +1116,7 @@ std::string TextBuffer::GenHTML(const TextAndColor& rows, const int fontHeightPo
bool hasWrittenAnyText = false;
std::optional<COLORREF> fgColor = std::nullopt;
std::optional<COLORREF> bkColor = std::nullopt;
for (UINT row = 0; row < rows.text.size(); row++)
for (size_t row = 0; row < rows.text.size(); row++)
{
size_t startOffset = 0;
@ -1118,25 +1125,25 @@ std::string TextBuffer::GenHTML(const TextAndColor& rows, const int fontHeightPo
htmlBuilder << "<BR>";
}
for (UINT col = 0; col < rows.text[row].length(); col++)
for (size_t col = 0; col < rows.text.at(row).length(); col++)
{
// do not include \r nor \n as they don't have attributes
// and are not HTML friendly. For line break use '<BR>' instead.
bool isLastCharInRow =
col == rows.text[row].length() - 1 ||
rows.text[row][col + 1] == '\r' ||
rows.text[row][col + 1] == '\n';
const bool isLastCharInRow =
col == rows.text.at(row).length() - 1 ||
rows.text.at(row).at(col + 1) == '\r' ||
rows.text.at(row).at(col + 1) == '\n';
bool colorChanged = false;
if (!fgColor.has_value() || rows.FgAttr[row][col] != fgColor.value())
if (!fgColor.has_value() || rows.FgAttr.at(row).at(col) != fgColor.value())
{
fgColor = rows.FgAttr[row][col];
fgColor = rows.FgAttr.at(row).at(col);
colorChanged = true;
}
if (!bkColor.has_value() || rows.BkAttr[row][col] != bkColor.value())
if (!bkColor.has_value() || rows.BkAttr.at(row).at(col) != bkColor.value())
{
bkColor = rows.BkAttr[row][col];
bkColor = rows.BkAttr.at(row).at(col);
colorChanged = true;
}
@ -1145,7 +1152,7 @@ std::string TextBuffer::GenHTML(const TextAndColor& rows, const int fontHeightPo
{
// note: this should be escaped (for '<', '>', and '&'),
// however MS Word doesn't appear to support HTML entities
htmlBuilder << ConvertToA(CP_UTF8, std::wstring_view(rows.text[row].data() + startOffset, col - startOffset + includeCurrent));
htmlBuilder << ConvertToA(CP_UTF8, std::wstring_view(rows.text.at(row)).substr(startOffset, col - startOffset + includeCurrent));
startOffset = col;
}
};

View file

@ -72,7 +72,7 @@ public:
~TextBuffer() = default;
// Used for duplicating properties to another text buffer
void CopyProperties(const TextBuffer& OtherBuffer);
void CopyProperties(const TextBuffer& OtherBuffer) noexcept;
// row manipulation
const ROW& GetRowByOffset(const size_t index) const;
@ -107,16 +107,16 @@ public:
COORD GetLastNonSpaceCharacter() const;
COORD GetLastNonSpaceCharacter(const Microsoft::Console::Types::Viewport viewport) const;
Cursor& GetCursor();
const Cursor& GetCursor() const;
Cursor& GetCursor() noexcept;
const Cursor& GetCursor() const noexcept;
const SHORT GetFirstRowIndex() const;
const SHORT GetFirstRowIndex() const noexcept;
const Microsoft::Console::Types::Viewport GetSize() const;
void ScrollRows(const SHORT firstRow, const SHORT size, const SHORT delta);
UINT TotalRowCount() const;
UINT TotalRowCount() const noexcept;
[[nodiscard]] TextAttribute GetCurrentAttributes() const noexcept;
@ -124,12 +124,12 @@ public:
void Reset();
[[nodiscard]] HRESULT ResizeTraditional(const COORD newSize) noexcept;
[[nodiscard]] HRESULT ResizeTraditional(const COORD newSize);
const UnicodeStorage& GetUnicodeStorage() const;
UnicodeStorage& GetUnicodeStorage();
const UnicodeStorage& GetUnicodeStorage() const noexcept;
UnicodeStorage& GetUnicodeStorage() noexcept;
Microsoft::Console::Render::IRenderTarget& GetRenderTarget();
Microsoft::Console::Render::IRenderTarget& GetRenderTarget() noexcept;
class TextAndColor
{
@ -165,7 +165,7 @@ private:
Microsoft::Console::Render::IRenderTarget& _renderTarget;
void _SetFirstRowIndex(const SHORT FirstRowIndex);
void _SetFirstRowIndex(const SHORT FirstRowIndex) noexcept;
COORD _GetPreviousFromCursor() const;

View file

@ -65,7 +65,7 @@ TextBufferCellIterator::operator bool() const noexcept
// - it - The other iterator to compare to this one.
// Return Value:
// - True if it's the same text buffer and same cell position. False otherwise.
bool TextBufferCellIterator::operator==(const TextBufferCellIterator& it) const noexcept
bool TextBufferCellIterator::operator==(const TextBufferCellIterator& it) const
{
return _pos == it._pos &&
&_buffer == &it._buffer &&
@ -81,7 +81,7 @@ bool TextBufferCellIterator::operator==(const TextBufferCellIterator& it) const
// - it - The other iterator to compare to this one.
// Return Value:
// - True if it's the same text buffer and different cell position or if they're different buffers. False otherwise.
bool TextBufferCellIterator::operator!=(const TextBufferCellIterator& it) const noexcept
bool TextBufferCellIterator::operator!=(const TextBufferCellIterator& it) const
{
return !(*this == it);
}
@ -212,7 +212,7 @@ void TextBufferCellIterator::_SetPos(const COORD newPos)
if (newPos.X != _pos.X)
{
const ptrdiff_t diff = newPos.X - _pos.X;
const auto diff = gsl::narrow_cast<ptrdiff_t>(newPos.X) - gsl::narrow_cast<ptrdiff_t>(_pos.X);
_attrIter += diff;
}

View file

@ -28,12 +28,10 @@ public:
TextBufferCellIterator(const TextBuffer& buffer, COORD pos);
TextBufferCellIterator(const TextBuffer& buffer, COORD pos, const Microsoft::Console::Types::Viewport limits);
~TextBufferCellIterator() = default;
operator bool() const noexcept;
bool operator==(const TextBufferCellIterator& it) const noexcept;
bool operator!=(const TextBufferCellIterator& it) const noexcept;
bool operator==(const TextBufferCellIterator& it) const;
bool operator!=(const TextBufferCellIterator& it) const;
TextBufferCellIterator& operator+=(const ptrdiff_t& movement);
TextBufferCellIterator& operator-=(const ptrdiff_t& movement);

View file

@ -16,7 +16,7 @@ using namespace Microsoft::Console::Types;
// - Narrows the view of a cell iterator into a text only iterator.
// Arguments:
// - A cell iterator
TextBufferTextIterator::TextBufferTextIterator(const TextBufferCellIterator& cellIt) :
TextBufferTextIterator::TextBufferTextIterator(const TextBufferCellIterator& cellIt) noexcept :
TextBufferCellIterator(cellIt)
{
}
@ -25,7 +25,8 @@ TextBufferTextIterator::TextBufferTextIterator(const TextBufferCellIterator& cel
// - Returns the text information from the text buffer position addressed by this iterator.
// Return Value:
// - Read only UTF-16 text data
const std::wstring_view TextBufferTextIterator::operator*() const
// TODO GH 2682, fix design so this doesn't have to be suppressed.
[[gsl::suppress(26434)]] const std::wstring_view TextBufferTextIterator::operator*() const noexcept
{
return _view.Chars();
}
@ -34,7 +35,8 @@ const std::wstring_view TextBufferTextIterator::operator*() const
// - Returns the text information from the text buffer position addressed by this iterator.
// Return Value:
// - Read only UTF-16 text data
const std::wstring_view* TextBufferTextIterator::operator->() const
// TODO GH 2682, fix design so this doesn't have to be suppressed.
[[gsl::suppress(26434)]] const std::wstring_view* TextBufferTextIterator::operator->() const noexcept
{
return &_view.Chars();
}

View file

@ -22,10 +22,10 @@ class SCREEN_INFORMATION;
class TextBufferTextIterator final : public TextBufferCellIterator
{
public:
TextBufferTextIterator(const TextBufferCellIterator& cellIter);
TextBufferTextIterator(const TextBufferCellIterator& cellIter) noexcept;
const std::wstring_view operator*() const;
const std::wstring_view* operator->() const;
const std::wstring_view operator*() const noexcept;
const std::wstring_view* operator->() const noexcept;
protected:
#if UNIT_TESTING

View file

@ -9,6 +9,7 @@
<application>
<!-- Windows 10 1903 -->
<!-- See https://docs.microsoft.com/en-us/windows/apps/desktop/modernize/xaml-islands -->
<!-- "maxversiontested" is CASE SENSITIVE. Do not change this.-->
<maxversiontested Id="10.0.18362.0"/>
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>

View file

@ -26,6 +26,10 @@ constexpr COLORREF DEFAULT_BACKGROUND_WITH_ALPHA = OPACITY_OPAQUE | DEFAULT_BACK
constexpr COLORREF POWERSHELL_BLUE = RGB(1, 36, 86);
constexpr short DEFAULT_HISTORY_SIZE = 9001;
#pragma warning(push)
#pragma warning(disable : 26426)
// TODO GH 2674, don't disable this warning, move to std::wstring_view or something like that.
const std::wstring DEFAULT_FONT_FACE{ L"Consolas" };
constexpr int DEFAULT_FONT_SIZE = 12;
@ -39,3 +43,4 @@ constexpr COLORREF DEFAULT_CURSOR_COLOR = COLOR_WHITE;
constexpr COLORREF DEFAULT_CURSOR_HEIGHT = 25;
const std::wstring DEFAULT_WORD_DELIMITERS{ L" ./\\()\"'-:,.;<>~!@#$%^&*|+=[]{}~?\u2502" };
#pragma warning(pop)

View file

@ -22,6 +22,7 @@
<ClInclude Include="..\..\inc\IRenderData.hpp" />
<ClInclude Include="..\..\inc\IRenderEngine.hpp" />
<ClInclude Include="..\..\inc\IRenderer.hpp" />
<ClInclude Include="..\..\inc\IRenderTarget.hpp" />
<ClInclude Include="..\..\inc\RenderEngineBase.hpp" />
<ClInclude Include="..\precomp.h" />
<ClInclude Include="..\renderer.hpp" />

View file

@ -80,6 +80,9 @@
<ClInclude Include="..\..\inc\Cluster.hpp">
<Filter>Header Files\inc</Filter>
</ClInclude>
<ClInclude Include="..\..\inc\IRenderTarget.hpp">
<Filter>Header Files\inc</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />

View file

@ -20,16 +20,16 @@ using namespace Microsoft::Console::Render;
// - font - The DirectWrite font face to use while calculating layout (by default, will fallback if necessary)
// - clusters - From the backing buffer, the text to be displayed clustered by the columns it should consume.
// - width - The count of pixels available per column (the expected pixel width of every column)
CustomTextLayout::CustomTextLayout(IDWriteFactory1* const factory,
IDWriteTextAnalyzer1* const analyzer,
IDWriteTextFormat* const format,
IDWriteFontFace1* const font,
CustomTextLayout::CustomTextLayout(gsl::not_null<IDWriteFactory1*> const factory,
gsl::not_null<IDWriteTextAnalyzer1*> const analyzer,
gsl::not_null<IDWriteTextFormat*> const format,
gsl::not_null<IDWriteFontFace1*> const font,
std::basic_string_view<Cluster> const clusters,
size_t const width) :
_factory{ factory },
_analyzer{ analyzer },
_format{ format },
_font{ font },
_factory{ factory.get() },
_analyzer{ analyzer.get() },
_format{ format.get() },
_font{ font.get() },
_localeName{},
_numberSubstitution{},
_readingDirection{ DWRITE_READING_DIRECTION_LEFT_TO_RIGHT },
@ -39,7 +39,7 @@ CustomTextLayout::CustomTextLayout(IDWriteFactory1* const factory,
_width{ width }
{
// Fetch the locale name out once now from the format
_localeName.resize(format->GetLocaleNameLength() + 1); // +1 for null
_localeName.resize(gsl::narrow_cast<size_t>(format->GetLocaleNameLength()) + 1); // +1 for null
THROW_IF_FAILED(format->GetLocaleName(_localeName.data(), gsl::narrow<UINT32>(_localeName.size())));
for (const auto& cluster : clusters)
@ -58,6 +58,7 @@ CustomTextLayout::CustomTextLayout(IDWriteFactory1* const factory,
// - S_OK or suitable DirectX/DirectWrite/Direct2D result code.
[[nodiscard]] HRESULT STDMETHODCALLTYPE CustomTextLayout::GetColumns(_Out_ UINT32* columns)
{
RETURN_HR_IF_NULL(E_INVALIDARG, columns);
*columns = 0;
RETURN_IF_FAILED(_AnalyzeRuns());
@ -88,7 +89,7 @@ CustomTextLayout::CustomTextLayout(IDWriteFactory1* const factory,
[[nodiscard]] HRESULT STDMETHODCALLTYPE CustomTextLayout::Draw(_In_opt_ void* clientDrawingContext,
_In_ IDWriteTextRenderer* renderer,
FLOAT originX,
FLOAT originY)
FLOAT originY) noexcept
{
RETURN_IF_FAILED(_AnalyzeRuns());
RETURN_IF_FAILED(_ShapeGlyphRuns());
@ -146,7 +147,7 @@ CustomTextLayout::CustomTextLayout(IDWriteFactory1* const factory,
}
// Resequence the resulting runs in order before returning to caller.
size_t totalRuns = _runs.size();
const size_t totalRuns = _runs.size();
std::vector<LinkedRun> runs;
runs.resize(totalRuns);
@ -178,7 +179,7 @@ CustomTextLayout::CustomTextLayout(IDWriteFactory1* const factory,
const auto textLength = gsl::narrow<UINT32>(_text.size());
// Estimate the maximum number of glyph indices needed to hold a string.
UINT32 estimatedGlyphCount = _EstimateGlyphCount(textLength);
const UINT32 estimatedGlyphCount = _EstimateGlyphCount(textLength);
_glyphIndices.resize(estimatedGlyphCount);
_glyphOffsets.resize(estimatedGlyphCount);
@ -230,9 +231,9 @@ CustomTextLayout::CustomTextLayout(IDWriteFactory1* const factory,
// will shape as if the line is not broken.
Run& run = _runs.at(runIndex);
UINT32 textStart = run.textStart;
UINT32 textLength = run.textLength;
UINT32 maxGlyphCount = static_cast<UINT32>(_glyphIndices.size() - glyphStart);
const UINT32 textStart = run.textStart;
const UINT32 textLength = run.textLength;
UINT32 maxGlyphCount = gsl::narrow<UINT32>(_glyphIndices.size() - glyphStart);
UINT32 actualGlyphCount = 0;
run.glyphStart = glyphStart;
@ -268,7 +269,7 @@ CustomTextLayout::CustomTextLayout(IDWriteFactory1* const factory,
do
{
hr = _analyzer->GetGlyphs(
&_text[textStart],
&_text.at(textStart),
textLength,
run.fontFace.Get(),
run.isSideways, // isSideways,
@ -280,10 +281,10 @@ CustomTextLayout::CustomTextLayout(IDWriteFactory1* const factory,
nullptr, // featureLengths
0, // featureCount
maxGlyphCount, // maxGlyphCount
&_glyphClusters[textStart],
&textProps[0],
&_glyphIndices[glyphStart],
&glyphProps[0],
&_glyphClusters.at(textStart),
&textProps.at(0),
&_glyphIndices.at(glyphStart),
&glyphProps.at(0),
&actualGlyphCount);
tries++;
@ -291,7 +292,7 @@ CustomTextLayout::CustomTextLayout(IDWriteFactory1* const factory,
{
// Try again using a larger buffer.
maxGlyphCount = _EstimateGlyphCount(maxGlyphCount);
UINT32 totalGlyphsArrayCount = glyphStart + maxGlyphCount;
const UINT32 totalGlyphsArrayCount = glyphStart + maxGlyphCount;
glyphProps.resize(maxGlyphCount);
_glyphIndices.resize(totalGlyphsArrayCount);
@ -306,19 +307,19 @@ CustomTextLayout::CustomTextLayout(IDWriteFactory1* const factory,
// Get the placement of the all the glyphs.
_glyphAdvances.resize(std::max(static_cast<size_t>(glyphStart + actualGlyphCount), _glyphAdvances.size()));
_glyphOffsets.resize(std::max(static_cast<size_t>(glyphStart + actualGlyphCount), _glyphOffsets.size()));
_glyphAdvances.resize(std::max(gsl::narrow_cast<size_t>(glyphStart) + gsl::narrow_cast<size_t>(actualGlyphCount), _glyphAdvances.size()));
_glyphOffsets.resize(std::max(gsl::narrow_cast<size_t>(glyphStart) + gsl::narrow_cast<size_t>(actualGlyphCount), _glyphOffsets.size()));
const auto fontSizeFormat = _format->GetFontSize();
const auto fontSize = fontSizeFormat * run.fontScale;
hr = _analyzer->GetGlyphPlacements(
&_text[textStart],
&_glyphClusters[textStart],
&textProps[0],
&_text.at(textStart),
&_glyphClusters.at(textStart),
&textProps.at(0),
textLength,
&_glyphIndices[glyphStart],
&glyphProps[0],
&_glyphIndices.at(glyphStart),
&glyphProps.at(0),
actualGlyphCount,
run.fontFace.Get(),
fontSize,
@ -329,8 +330,8 @@ CustomTextLayout::CustomTextLayout(IDWriteFactory1* const factory,
NULL, // features
NULL, // featureRangeLengths
0, // featureRanges
&_glyphAdvances[glyphStart],
&_glyphOffsets[glyphStart]);
&_glyphAdvances.at(glyphStart),
&_glyphOffsets.at(glyphStart));
RETURN_IF_FAILED(hr);
@ -391,13 +392,13 @@ CustomTextLayout::CustomTextLayout(IDWriteFactory1* const factory,
for (auto i = run.glyphStart; i < (run.glyphStart + run.glyphCount); i++)
{
// Advance is how wide in pixels the glyph is
auto& advance = _glyphAdvances[i];
auto& advance = _glyphAdvances.at(i);
// Offsets is how far to move the origin (in pixels) from where it is
auto& offset = _glyphOffsets[i];
auto& offset = _glyphOffsets.at(i);
// Get how many columns we expected the glyph to have and mutiply into pixels.
const auto columns = _textClusterColumns[i];
const auto columns = _textClusterColumns.at(i);
const auto advanceExpected = static_cast<float>(columns * _width);
// If what we expect is bigger than what we have... pad it out.
@ -419,7 +420,7 @@ CustomTextLayout::CustomTextLayout(IDWriteFactory1* const factory,
// We need to retrieve the design information for this specific glyph so we can figure out the appropriate
// height proportional to the width that we desire.
INT32 advanceInDesignUnits;
RETURN_IF_FAILED(run.fontFace->GetDesignGlyphAdvances(1, &_glyphIndices[i], &advanceInDesignUnits));
RETURN_IF_FAILED(run.fontFace->GetDesignGlyphAdvances(1, &_glyphIndices.at(i), &advanceInDesignUnits));
// When things are drawn, we want the font size (as specified in the base font in the original format)
// to be scaled by some factor.
@ -467,6 +468,8 @@ CustomTextLayout::CustomTextLayout(IDWriteFactory1* const factory,
IDWriteTextRenderer* renderer,
const D2D_POINT_2F origin) noexcept
{
RETURN_HR_IF_NULL(E_INVALIDARG, renderer);
try
{
// We're going to start from the origin given and walk to the right for each
@ -477,21 +480,21 @@ CustomTextLayout::CustomTextLayout(IDWriteFactory1* const factory,
for (UINT32 runIndex = 0; runIndex < _runs.size(); ++runIndex)
{
// Get the run
Run& run = _runs.at(runIndex);
const Run& run = _runs.at(runIndex);
// Prepare the glyph run and description objects by converting our
// internal storage representation into something that matches DWrite's structures.
DWRITE_GLYPH_RUN glyphRun = { 0 };
DWRITE_GLYPH_RUN glyphRun;
glyphRun.bidiLevel = run.bidiLevel;
glyphRun.fontEmSize = _format->GetFontSize() * run.fontScale;
glyphRun.fontFace = run.fontFace.Get();
glyphRun.glyphAdvances = _glyphAdvances.data() + run.glyphStart;
glyphRun.glyphAdvances = &_glyphAdvances.at(run.glyphStart);
glyphRun.glyphCount = run.glyphCount;
glyphRun.glyphIndices = _glyphIndices.data() + run.glyphStart;
glyphRun.glyphOffsets = _glyphOffsets.data() + run.glyphStart;
glyphRun.glyphIndices = &_glyphIndices.at(run.glyphStart);
glyphRun.glyphOffsets = &_glyphOffsets.at(run.glyphStart);
glyphRun.isSideways = false;
DWRITE_GLYPH_RUN_DESCRIPTION glyphRunDescription = { 0 };
DWRITE_GLYPH_RUN_DESCRIPTION glyphRunDescription;
glyphRunDescription.clusterMap = _glyphClusters.data();
glyphRunDescription.localeName = _localeName.data();
glyphRunDescription.string = _text.data();
@ -539,7 +542,7 @@ CustomTextLayout::CustomTextLayout(IDWriteFactory1* const factory,
// Return Value:
// - An estimate of how many glyph spaces may be required in the shaping arrays
// to hold the data from a string of the given length.
[[nodiscard]] UINT32 CustomTextLayout::_EstimateGlyphCount(const UINT32 textLength) noexcept
[[nodiscard]] constexpr UINT32 CustomTextLayout::_EstimateGlyphCount(const UINT32 textLength) noexcept
{
// This formula is from https://docs.microsoft.com/en-us/windows/desktop/api/dwrite/nf-dwrite-idwritetextanalyzer-getglyphs
// and is the recommended formula for estimating buffer size for glyph count.
@ -561,12 +564,15 @@ CustomTextLayout::CustomTextLayout(IDWriteFactory1* const factory,
_Outptr_result_buffer_(*textLength) WCHAR const** textString,
_Out_ UINT32* textLength)
{
RETURN_HR_IF_NULL(E_INVALIDARG, textString);
RETURN_HR_IF_NULL(E_INVALIDARG, textLength);
*textString = nullptr;
*textLength = 0;
if (textPosition < _text.size())
{
*textString = _text.data() + textPosition;
*textString = &_text.at(textPosition);
*textLength = gsl::narrow<UINT32>(_text.size()) - textPosition;
}
@ -585,8 +591,11 @@ CustomTextLayout::CustomTextLayout(IDWriteFactory1* const factory,
// - S_OK or appropriate STL/GSL failure code.
[[nodiscard]] HRESULT STDMETHODCALLTYPE CustomTextLayout::GetTextBeforePosition(UINT32 textPosition,
_Outptr_result_buffer_(*textLength) WCHAR const** textString,
_Out_ UINT32* textLength)
_Out_ UINT32* textLength) noexcept
{
RETURN_HR_IF_NULL(E_INVALIDARG, textString);
RETURN_HR_IF_NULL(E_INVALIDARG, textLength);
*textString = nullptr;
*textLength = 0;
@ -606,7 +615,7 @@ CustomTextLayout::CustomTextLayout(IDWriteFactory1* const factory,
// - <none>
// Return Value:
// - The reading direction held for this layout from construction
[[nodiscard]] DWRITE_READING_DIRECTION STDMETHODCALLTYPE CustomTextLayout::GetParagraphReadingDirection()
[[nodiscard]] DWRITE_READING_DIRECTION STDMETHODCALLTYPE CustomTextLayout::GetParagraphReadingDirection() noexcept
{
return _readingDirection;
}
@ -622,8 +631,11 @@ CustomTextLayout::CustomTextLayout(IDWriteFactory1* const factory,
// - S_OK or appropriate STL/GSL failure code.
[[nodiscard]] HRESULT STDMETHODCALLTYPE CustomTextLayout::GetLocaleName(UINT32 textPosition,
_Out_ UINT32* textLength,
_Outptr_result_z_ WCHAR const** localeName)
_Outptr_result_z_ WCHAR const** localeName) noexcept
{
RETURN_HR_IF_NULL(E_INVALIDARG, textLength);
RETURN_HR_IF_NULL(E_INVALIDARG, localeName);
*localeName = _localeName.data();
*textLength = gsl::narrow<UINT32>(_text.size()) - textPosition;
@ -641,8 +653,11 @@ CustomTextLayout::CustomTextLayout(IDWriteFactory1* const factory,
// - S_OK or appropriate STL/GSL failure code.
[[nodiscard]] HRESULT STDMETHODCALLTYPE CustomTextLayout::GetNumberSubstitution(UINT32 textPosition,
_Out_ UINT32* textLength,
_COM_Outptr_ IDWriteNumberSubstitution** numberSubstitution)
_COM_Outptr_ IDWriteNumberSubstitution** numberSubstitution) noexcept
{
RETURN_HR_IF_NULL(E_INVALIDARG, textLength);
RETURN_HR_IF_NULL(E_INVALIDARG, numberSubstitution);
*numberSubstitution = nullptr;
*textLength = gsl::narrow<UINT32>(_text.size()) - textPosition;
@ -799,7 +814,7 @@ CustomTextLayout::CustomTextLayout(IDWriteFactory1* const factory,
RETURN_IF_FAILED(format1->GetFontCollection(&collection));
std::wstring familyName;
familyName.resize(format1->GetFontFamilyNameLength() + 1);
familyName.resize(gsl::narrow_cast<size_t>(format1->GetFontFamilyNameLength()) + 1);
RETURN_IF_FAILED(format1->GetFontFamilyName(familyName.data(), gsl::narrow<UINT32>(familyName.size())));
const auto weight = format1->GetFontWeight();
@ -912,7 +927,7 @@ CustomTextLayout::CustomTextLayout(IDWriteFactory1* const factory,
if (textLength < runTextLength)
{
runTextLength = textLength; // Limit to what's actually left.
UINT32 runTextStart = run.textStart;
const UINT32 runTextStart = run.textStart;
_SplitCurrentRun(runTextStart + runTextLength);
}
@ -940,12 +955,12 @@ CustomTextLayout::CustomTextLayout(IDWriteFactory1* const factory,
// - <none> - Updates internal state
void CustomTextLayout::_SetCurrentRun(const UINT32 textPosition)
{
if (_runIndex < _runs.size() && _runs[_runIndex].ContainsTextPosition(textPosition))
if (_runIndex < _runs.size() && _runs.at(_runIndex).ContainsTextPosition(textPosition))
{
return;
}
_runIndex = static_cast<UINT32>(
_runIndex = gsl::narrow<UINT32>(
std::find(_runs.begin(), _runs.end(), textPosition) - _runs.begin());
}
@ -957,13 +972,13 @@ void CustomTextLayout::_SetCurrentRun(const UINT32 textPosition)
// - <none> - Updates internal state, the back half will be selected after running
void CustomTextLayout::_SplitCurrentRun(const UINT32 splitPosition)
{
UINT32 runTextStart = _runs.at(_runIndex).textStart;
const UINT32 runTextStart = _runs.at(_runIndex).textStart;
if (splitPosition <= runTextStart)
return; // no change
// Grow runs by one.
size_t totalRuns = _runs.size();
const size_t totalRuns = _runs.size();
try
{
_runs.resize(totalRuns + 1);
@ -974,16 +989,16 @@ void CustomTextLayout::_SplitCurrentRun(const UINT32 splitPosition)
}
// Copy the old run to the end.
LinkedRun& frontHalf = _runs[_runIndex];
LinkedRun& frontHalf = _runs.at(_runIndex);
LinkedRun& backHalf = _runs.back();
backHalf = frontHalf;
// Adjust runs' text positions and lengths.
UINT32 splitPoint = splitPosition - runTextStart;
const UINT32 splitPoint = splitPosition - runTextStart;
backHalf.textStart += splitPoint;
backHalf.textLength -= splitPoint;
frontHalf.textLength = splitPoint;
frontHalf.nextRunIndex = static_cast<UINT32>(totalRuns);
_runIndex = static_cast<UINT32>(totalRuns);
frontHalf.nextRunIndex = gsl::narrow<UINT32>(totalRuns);
_runIndex = gsl::narrow<UINT32>(totalRuns);
}
#pragma endregion

View file

@ -19,10 +19,10 @@ namespace Microsoft::Console::Render
public:
// Based on the Windows 7 SDK sample at https://github.com/pauldotknopf/WindowsSDK7-Samples/tree/master/multimedia/DirectWrite/CustomLayout
CustomTextLayout(IDWriteFactory1* const factory,
IDWriteTextAnalyzer1* const analyzer,
IDWriteTextFormat* const format,
IDWriteFontFace1* const font,
CustomTextLayout(gsl::not_null<IDWriteFactory1*> const factory,
gsl::not_null<IDWriteTextAnalyzer1*> const analyzer,
gsl::not_null<IDWriteTextFormat*> const format,
gsl::not_null<IDWriteFontFace1*> const font,
const std::basic_string_view<::Microsoft::Console::Render::Cluster> clusters,
size_t const width);
@ -32,43 +32,43 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT STDMETHODCALLTYPE Draw(_In_opt_ void* clientDrawingContext,
_In_ IDWriteTextRenderer* renderer,
FLOAT originX,
FLOAT originY);
FLOAT originY) noexcept;
// IDWriteTextAnalysisSource methods
[[nodiscard]] virtual HRESULT STDMETHODCALLTYPE GetTextAtPosition(UINT32 textPosition,
_Outptr_result_buffer_(*textLength) WCHAR const** textString,
_Out_ UINT32* textLength) override;
[[nodiscard]] virtual HRESULT STDMETHODCALLTYPE GetTextBeforePosition(UINT32 textPosition,
_Outptr_result_buffer_(*textLength) WCHAR const** textString,
_Out_ UINT32* textLength) override;
[[nodiscard]] virtual DWRITE_READING_DIRECTION STDMETHODCALLTYPE GetParagraphReadingDirection() override;
[[nodiscard]] virtual HRESULT STDMETHODCALLTYPE GetLocaleName(UINT32 textPosition,
[[nodiscard]] HRESULT STDMETHODCALLTYPE GetTextAtPosition(UINT32 textPosition,
_Outptr_result_buffer_(*textLength) WCHAR const** textString,
_Out_ UINT32* textLength) override;
[[nodiscard]] HRESULT STDMETHODCALLTYPE GetTextBeforePosition(UINT32 textPosition,
_Outptr_result_buffer_(*textLength) WCHAR const** textString,
_Out_ UINT32* textLength) noexcept override;
[[nodiscard]] DWRITE_READING_DIRECTION STDMETHODCALLTYPE GetParagraphReadingDirection() noexcept override;
[[nodiscard]] HRESULT STDMETHODCALLTYPE GetLocaleName(UINT32 textPosition,
_Out_ UINT32* textLength,
_Outptr_result_z_ WCHAR const** localeName) noexcept override;
[[nodiscard]] HRESULT STDMETHODCALLTYPE GetNumberSubstitution(UINT32 textPosition,
_Out_ UINT32* textLength,
_Outptr_result_z_ WCHAR const** localeName) override;
[[nodiscard]] virtual HRESULT STDMETHODCALLTYPE GetNumberSubstitution(UINT32 textPosition,
_Out_ UINT32* textLength,
_COM_Outptr_ IDWriteNumberSubstitution** numberSubstitution) override;
_COM_Outptr_ IDWriteNumberSubstitution** numberSubstitution) noexcept override;
// IDWriteTextAnalysisSink methods
[[nodiscard]] virtual HRESULT STDMETHODCALLTYPE SetScriptAnalysis(UINT32 textPosition,
UINT32 textLength,
_In_ DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis) override;
[[nodiscard]] virtual HRESULT STDMETHODCALLTYPE SetLineBreakpoints(UINT32 textPosition,
UINT32 textLength,
_In_reads_(textLength) DWRITE_LINE_BREAKPOINT const* lineBreakpoints) override;
[[nodiscard]] virtual HRESULT STDMETHODCALLTYPE SetBidiLevel(UINT32 textPosition,
UINT32 textLength,
UINT8 explicitLevel,
UINT8 resolvedLevel) override;
[[nodiscard]] virtual HRESULT STDMETHODCALLTYPE SetNumberSubstitution(UINT32 textPosition,
UINT32 textLength,
_In_ IDWriteNumberSubstitution* numberSubstitution) override;
[[nodiscard]] HRESULT STDMETHODCALLTYPE SetScriptAnalysis(UINT32 textPosition,
UINT32 textLength,
_In_ DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis) override;
[[nodiscard]] HRESULT STDMETHODCALLTYPE SetLineBreakpoints(UINT32 textPosition,
UINT32 textLength,
_In_reads_(textLength) DWRITE_LINE_BREAKPOINT const* lineBreakpoints) override;
[[nodiscard]] HRESULT STDMETHODCALLTYPE SetBidiLevel(UINT32 textPosition,
UINT32 textLength,
UINT8 explicitLevel,
UINT8 resolvedLevel) override;
[[nodiscard]] HRESULT STDMETHODCALLTYPE SetNumberSubstitution(UINT32 textPosition,
UINT32 textLength,
_In_ IDWriteNumberSubstitution* numberSubstitution) override;
protected:
// A single contiguous run of characters containing the same analysis results.
struct Run
{
Run() :
Run() noexcept :
textStart(),
textLength(),
glyphStart(),
@ -93,12 +93,12 @@ namespace Microsoft::Console::Render
::Microsoft::WRL::ComPtr<IDWriteFontFace1> fontFace;
FLOAT fontScale;
inline bool ContainsTextPosition(UINT32 desiredTextPosition) const
inline bool ContainsTextPosition(UINT32 desiredTextPosition) const noexcept
{
return desiredTextPosition >= textStart && desiredTextPosition < textStart + textLength;
}
inline bool operator==(UINT32 desiredTextPosition) const
inline bool operator==(UINT32 desiredTextPosition) const noexcept
{
// Search by text position using std::find
return ContainsTextPosition(desiredTextPosition);
@ -108,7 +108,7 @@ namespace Microsoft::Console::Render
// Single text analysis run, which points to the next run.
struct LinkedRun : Run
{
LinkedRun() :
LinkedRun() noexcept :
nextRunIndex(0)
{
}
@ -132,7 +132,7 @@ namespace Microsoft::Console::Render
IDWriteTextRenderer* renderer,
const D2D_POINT_2F origin) noexcept;
[[nodiscard]] static UINT32 _EstimateGlyphCount(const UINT32 textLength) noexcept;
[[nodiscard]] static constexpr UINT32 _EstimateGlyphCount(const UINT32 textLength) noexcept;
private:
const ::Microsoft::WRL::ComPtr<IDWriteFactory1> _factory;

View file

@ -21,8 +21,10 @@ using namespace Microsoft::Console::Render;
// Return Value:
// - S_OK
[[nodiscard]] HRESULT CustomTextRenderer::IsPixelSnappingDisabled(void* /*clientDrawingContext*/,
_Out_ BOOL* isDisabled)
_Out_ BOOL* isDisabled) noexcept
{
RETURN_HR_IF_NULL(E_INVALIDARG, isDisabled);
*isDisabled = false;
return S_OK;
}
@ -38,9 +40,12 @@ using namespace Microsoft::Console::Render;
// Return Value:
// - S_OK
[[nodiscard]] HRESULT CustomTextRenderer::GetPixelsPerDip(void* clientDrawingContext,
_Out_ FLOAT* pixelsPerDip)
_Out_ FLOAT* pixelsPerDip) noexcept
{
DrawingContext* drawingContext = static_cast<DrawingContext*>(clientDrawingContext);
RETURN_HR_IF_NULL(E_INVALIDARG, pixelsPerDip);
const DrawingContext* drawingContext = static_cast<DrawingContext*>(clientDrawingContext);
RETURN_HR_IF_NULL(E_INVALIDARG, drawingContext);
float dpiX, dpiY;
drawingContext->renderTarget->GetDpi(&dpiX, &dpiY);
@ -58,12 +63,24 @@ using namespace Microsoft::Console::Render;
// Return Value:
// - S_OK
[[nodiscard]] HRESULT CustomTextRenderer::GetCurrentTransform(void* clientDrawingContext,
DWRITE_MATRIX* transform)
DWRITE_MATRIX* transform) noexcept
{
DrawingContext* drawingContext = static_cast<DrawingContext*>(clientDrawingContext);
RETURN_HR_IF_NULL(E_INVALIDARG, transform);
const DrawingContext* drawingContext = static_cast<DrawingContext*>(clientDrawingContext);
RETURN_HR_IF_NULL(E_INVALIDARG, drawingContext);
// Retrieve as D2D1 matrix then copy into DWRITE matrix.
D2D1_MATRIX_3X2_F d2d1Matrix{ 0 };
drawingContext->renderTarget->GetTransform(&d2d1Matrix);
transform->dx = d2d1Matrix.dx;
transform->dy = d2d1Matrix.dy;
transform->m11 = d2d1Matrix.m11;
transform->m12 = d2d1Matrix.m12;
transform->m21 = d2d1Matrix.m21;
transform->m22 = d2d1Matrix.m22;
// Matrix structures are defined identically
drawingContext->renderTarget->GetTransform((D2D1_MATRIX_3X2_F*)transform);
return S_OK;
}
#pragma endregion
@ -88,17 +105,16 @@ using namespace Microsoft::Console::Render;
FLOAT baselineOriginX,
FLOAT baselineOriginY,
_In_ const DWRITE_UNDERLINE* underline,
IUnknown* clientDrawingEffect)
IUnknown* clientDrawingEffect) noexcept
{
_FillRectangle(clientDrawingContext,
clientDrawingEffect,
baselineOriginX,
baselineOriginY + underline->offset,
underline->width,
underline->thickness,
underline->readingDirection,
underline->flowDirection);
return S_OK;
return _FillRectangle(clientDrawingContext,
clientDrawingEffect,
baselineOriginX,
baselineOriginY + underline->offset,
underline->width,
underline->thickness,
underline->readingDirection,
underline->flowDirection);
}
// Routine Description:
@ -120,17 +136,16 @@ using namespace Microsoft::Console::Render;
FLOAT baselineOriginX,
FLOAT baselineOriginY,
_In_ const DWRITE_STRIKETHROUGH* strikethrough,
IUnknown* clientDrawingEffect)
IUnknown* clientDrawingEffect) noexcept
{
_FillRectangle(clientDrawingContext,
clientDrawingEffect,
baselineOriginX,
baselineOriginY + strikethrough->offset,
strikethrough->width,
strikethrough->thickness,
strikethrough->readingDirection,
strikethrough->flowDirection);
return S_OK;
return _FillRectangle(clientDrawingContext,
clientDrawingEffect,
baselineOriginX,
baselineOriginY + strikethrough->offset,
strikethrough->width,
strikethrough->thickness,
strikethrough->readingDirection,
strikethrough->flowDirection);
}
// Routine Description:
@ -146,16 +161,17 @@ using namespace Microsoft::Console::Render;
// - flowDirection - textual flow information that could affect the rectangle
// Return Value:
// - S_OK
void CustomTextRenderer::_FillRectangle(void* clientDrawingContext,
IUnknown* clientDrawingEffect,
float x,
float y,
float width,
float thickness,
DWRITE_READING_DIRECTION /*readingDirection*/,
DWRITE_FLOW_DIRECTION /*flowDirection*/)
[[nodiscard]] HRESULT CustomTextRenderer::_FillRectangle(void* clientDrawingContext,
IUnknown* clientDrawingEffect,
float x,
float y,
float width,
float thickness,
DWRITE_READING_DIRECTION /*readingDirection*/,
DWRITE_FLOW_DIRECTION /*flowDirection*/) noexcept
{
DrawingContext* drawingContext = static_cast<DrawingContext*>(clientDrawingContext);
RETURN_HR_IF_NULL(E_INVALIDARG, drawingContext);
// Get brush
ID2D1Brush* brush = drawingContext->foregroundBrush;
@ -165,8 +181,10 @@ void CustomTextRenderer::_FillRectangle(void* clientDrawingContext,
brush = static_cast<ID2D1Brush*>(clientDrawingEffect);
}
D2D1_RECT_F rect = D2D1::RectF(x, y, x + width, y + thickness);
const D2D1_RECT_F rect = D2D1::RectF(x, y, x + width, y + thickness);
drawingContext->renderTarget->FillRectangle(&rect, brush);
return S_OK;
}
// Routine Description:
@ -189,8 +207,10 @@ void CustomTextRenderer::_FillRectangle(void* clientDrawingContext,
IDWriteInlineObject* inlineObject,
BOOL isSideways,
BOOL isRightToLeft,
IUnknown* clientDrawingEffect)
IUnknown* clientDrawingEffect) noexcept
{
RETURN_HR_IF_NULL(E_INVALIDARG, inlineObject);
return inlineObject->Draw(clientDrawingContext,
this,
originX,
@ -233,12 +253,11 @@ void CustomTextRenderer::_FillRectangle(void* clientDrawingContext,
// Since we've delegated the drawing of the background of the text into this function, the origin passed in isn't actually the baseline.
// It's the top left corner. Save that off first.
D2D1_POINT_2F origin = D2D1::Point2F(baselineOriginX, baselineOriginY);
const D2D1_POINT_2F origin = D2D1::Point2F(baselineOriginX, baselineOriginY);
// Then make a copy for the baseline origin (which is part way down the left side of the text, not the top or bottom).
// We'll use this baseline Origin for drawing the actual text.
D2D1_POINT_2F baselineOrigin = origin;
baselineOrigin.y += drawingContext->spacing.baseline;
const D2D1_POINT_2F baselineOrigin{ origin.x, origin.y + drawingContext->spacing.baseline };
::Microsoft::WRL::ComPtr<ID2D1DeviceContext> d2dContext;
RETURN_IF_FAILED(drawingContext->renderTarget->QueryInterface(d2dContext.GetAddressOf()));
@ -249,11 +268,9 @@ void CustomTextRenderer::_FillRectangle(void* clientDrawingContext,
rect.bottom = rect.top + drawingContext->cellSize.height;
rect.left = origin.x;
rect.right = rect.left;
const auto advancesSpan = gsl::make_span(glyphRun->glyphAdvances, glyphRun->glyphCount);
for (UINT32 i = 0; i < glyphRun->glyphCount; i++)
{
rect.right += glyphRun->glyphAdvances[i];
}
rect.right = std::accumulate(advancesSpan.cbegin(), advancesSpan.cend(), rect.right);
d2dContext->FillRectangle(rect, drawingContext->backgroundBrush);
@ -270,7 +287,7 @@ void CustomTextRenderer::_FillRectangle(void* clientDrawingContext,
RETURN_IF_FAILED(drawingContext->dwriteFactory->QueryInterface(dwriteFactory4.GetAddressOf()));
// The list of glyph image formats this renderer is prepared to support.
DWRITE_GLYPH_IMAGE_FORMATS supportedFormats =
const DWRITE_GLYPH_IMAGE_FORMATS supportedFormats =
DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE |
DWRITE_GLYPH_IMAGE_FORMATS_CFF |
DWRITE_GLYPH_IMAGE_FORMATS_COLR |
@ -283,14 +300,14 @@ void CustomTextRenderer::_FillRectangle(void* clientDrawingContext,
// Determine whether there are any color glyph runs within glyphRun. If
// there are, glyphRunEnumerator can be used to iterate through them.
::Microsoft::WRL::ComPtr<IDWriteColorGlyphRunEnumerator1> glyphRunEnumerator;
HRESULT hr = dwriteFactory4->TranslateColorGlyphRun(baselineOrigin,
glyphRun,
glyphRunDescription,
supportedFormats,
measuringMode,
nullptr,
0,
&glyphRunEnumerator);
const HRESULT hr = dwriteFactory4->TranslateColorGlyphRun(baselineOrigin,
glyphRun,
glyphRunDescription,
supportedFormats,
measuringMode,
nullptr,
0,
&glyphRunEnumerator);
// If the analysis found no color glyphs in the run, just draw normally.
if (hr == DWRITE_E_NOCOLOR)
@ -320,7 +337,7 @@ void CustomTextRenderer::_FillRectangle(void* clientDrawingContext,
DWRITE_COLOR_GLYPH_RUN1 const* colorRun;
RETURN_IF_FAILED(glyphRunEnumerator->GetCurrentRun(&colorRun));
D2D1_POINT_2F currentBaselineOrigin = D2D1::Point2F(colorRun->baselineOriginX, colorRun->baselineOriginY);
const D2D1_POINT_2F currentBaselineOrigin = D2D1::Point2F(colorRun->baselineOriginX, colorRun->baselineOriginY);
switch (colorRun->glyphImageFormat)
{
@ -357,7 +374,7 @@ void CustomTextRenderer::_FillRectangle(void* clientDrawingContext,
// This run is solid-color outlines, either from non-color
// glyphs or from COLR glyph layers. Use Direct2D to draw them.
ID2D1Brush* layerBrush;
ID2D1Brush* layerBrush{ nullptr };
// The rule is "if 0xffff, use current brush." See:
// https://docs.microsoft.com/en-us/windows/desktop/api/dwrite_2/ns-dwrite_2-dwrite_color_glyph_run
if (colorRun->paletteIndex == 0xFFFF)
@ -414,6 +431,11 @@ void CustomTextRenderer::_FillRectangle(void* clientDrawingContext,
_In_ const DWRITE_GLYPH_RUN_DESCRIPTION* glyphRunDescription,
ID2D1Brush* brush)
{
RETURN_HR_IF_NULL(E_INVALIDARG, clientDrawingContext);
RETURN_HR_IF_NULL(E_INVALIDARG, glyphRun);
RETURN_HR_IF_NULL(E_INVALIDARG, glyphRunDescription);
RETURN_HR_IF_NULL(E_INVALIDARG, brush);
::Microsoft::WRL::ComPtr<ID2D1DeviceContext> d2dContext;
RETURN_IF_FAILED(clientDrawingContext->renderTarget->QueryInterface(d2dContext.GetAddressOf()));
@ -433,8 +455,11 @@ void CustomTextRenderer::_FillRectangle(void* clientDrawingContext,
D2D1_POINT_2F baselineOrigin,
DWRITE_MEASURING_MODE /*measuringMode*/,
_In_ const DWRITE_GLYPH_RUN* glyphRun,
_In_ const DWRITE_GLYPH_RUN_DESCRIPTION* /*glyphRunDescription*/)
_In_ const DWRITE_GLYPH_RUN_DESCRIPTION* /*glyphRunDescription*/) noexcept
{
RETURN_HR_IF_NULL(E_INVALIDARG, clientDrawingContext);
RETURN_HR_IF_NULL(E_INVALIDARG, glyphRun);
// This is regular text but manually
::Microsoft::WRL::ComPtr<ID2D1Factory> d2dFactory;
clientDrawingContext->renderTarget->GetFactory(d2dFactory.GetAddressOf());
@ -473,8 +498,11 @@ void CustomTextRenderer::_FillRectangle(void* clientDrawingContext,
D2D1_POINT_2F baselineOrigin,
DWRITE_MEASURING_MODE /*measuringMode*/,
_In_ const DWRITE_GLYPH_RUN* glyphRun,
_In_ const DWRITE_GLYPH_RUN_DESCRIPTION* /*glyphRunDescription*/)
_In_ const DWRITE_GLYPH_RUN_DESCRIPTION* /*glyphRunDescription*/) noexcept
{
RETURN_HR_IF_NULL(E_INVALIDARG, clientDrawingContext);
RETURN_HR_IF_NULL(E_INVALIDARG, glyphRun);
// This is glow text manually
::Microsoft::WRL::ComPtr<ID2D1Factory> d2dFactory;
clientDrawingContext->renderTarget->GetFactory(d2dFactory.GetAddressOf());

View file

@ -15,7 +15,7 @@ namespace Microsoft::Console::Render
IDWriteFactory* dwriteFactory,
const DWRITE_LINE_SPACING spacing,
const D2D_SIZE_F cellSize,
const D2D1_DRAW_TEXT_OPTIONS options = D2D1_DRAW_TEXT_OPTIONS_NONE)
const D2D1_DRAW_TEXT_OPTIONS options = D2D1_DRAW_TEXT_OPTIONS_NONE) noexcept
{
this->renderTarget = renderTarget;
this->foregroundBrush = foregroundBrush;
@ -42,53 +42,53 @@ namespace Microsoft::Console::Render
// https://docs.microsoft.com/en-us/windows/desktop/DirectWrite/how-to-implement-a-custom-text-renderer
// IDWritePixelSnapping methods
[[nodiscard]] virtual HRESULT STDMETHODCALLTYPE IsPixelSnappingDisabled(void* clientDrawingContext,
_Out_ BOOL* isDisabled) override;
[[nodiscard]] HRESULT STDMETHODCALLTYPE IsPixelSnappingDisabled(void* clientDrawingContext,
_Out_ BOOL* isDisabled) noexcept override;
[[nodiscard]] virtual HRESULT STDMETHODCALLTYPE GetPixelsPerDip(void* clientDrawingContext,
_Out_ FLOAT* pixelsPerDip) override;
[[nodiscard]] HRESULT STDMETHODCALLTYPE GetPixelsPerDip(void* clientDrawingContext,
_Out_ FLOAT* pixelsPerDip) noexcept override;
[[nodiscard]] virtual HRESULT STDMETHODCALLTYPE GetCurrentTransform(void* clientDrawingContext,
_Out_ DWRITE_MATRIX* transform) override;
[[nodiscard]] HRESULT STDMETHODCALLTYPE GetCurrentTransform(void* clientDrawingContext,
_Out_ DWRITE_MATRIX* transform) noexcept override;
// IDWriteTextRenderer methods
[[nodiscard]] virtual HRESULT STDMETHODCALLTYPE DrawGlyphRun(void* clientDrawingContext,
FLOAT baselineOriginX,
FLOAT baselineOriginY,
DWRITE_MEASURING_MODE measuringMode,
_In_ const DWRITE_GLYPH_RUN* glyphRun,
_In_ const DWRITE_GLYPH_RUN_DESCRIPTION* glyphRunDescription,
IUnknown* clientDrawingEffect) override;
[[nodiscard]] HRESULT STDMETHODCALLTYPE DrawGlyphRun(void* clientDrawingContext,
FLOAT baselineOriginX,
FLOAT baselineOriginY,
DWRITE_MEASURING_MODE measuringMode,
_In_ const DWRITE_GLYPH_RUN* glyphRun,
_In_ const DWRITE_GLYPH_RUN_DESCRIPTION* glyphRunDescription,
IUnknown* clientDrawingEffect) override;
[[nodiscard]] virtual HRESULT STDMETHODCALLTYPE DrawUnderline(void* clientDrawingContext,
FLOAT baselineOriginX,
FLOAT baselineOriginY,
_In_ const DWRITE_UNDERLINE* underline,
IUnknown* clientDrawingEffect) override;
[[nodiscard]] HRESULT STDMETHODCALLTYPE DrawUnderline(void* clientDrawingContext,
FLOAT baselineOriginX,
FLOAT baselineOriginY,
_In_ const DWRITE_UNDERLINE* underline,
IUnknown* clientDrawingEffect) noexcept override;
[[nodiscard]] virtual HRESULT STDMETHODCALLTYPE DrawStrikethrough(void* clientDrawingContext,
FLOAT baselineOriginX,
FLOAT baselineOriginY,
_In_ const DWRITE_STRIKETHROUGH* strikethrough,
IUnknown* clientDrawingEffect) override;
[[nodiscard]] HRESULT STDMETHODCALLTYPE DrawStrikethrough(void* clientDrawingContext,
FLOAT baselineOriginX,
FLOAT baselineOriginY,
_In_ const DWRITE_STRIKETHROUGH* strikethrough,
IUnknown* clientDrawingEffect) noexcept override;
[[nodiscard]] virtual HRESULT STDMETHODCALLTYPE DrawInlineObject(void* clientDrawingContext,
FLOAT originX,
FLOAT originY,
IDWriteInlineObject* inlineObject,
BOOL isSideways,
BOOL isRightToLeft,
IUnknown* clientDrawingEffect) override;
[[nodiscard]] HRESULT STDMETHODCALLTYPE DrawInlineObject(void* clientDrawingContext,
FLOAT originX,
FLOAT originY,
IDWriteInlineObject* inlineObject,
BOOL isSideways,
BOOL isRightToLeft,
IUnknown* clientDrawingEffect) noexcept override;
private:
void _FillRectangle(void* clientDrawingContext,
IUnknown* clientDrawingEffect,
float x,
float y,
float width,
float thickness,
DWRITE_READING_DIRECTION readingDirection,
DWRITE_FLOW_DIRECTION flowDirection);
[[nodiscard]] HRESULT _FillRectangle(void* clientDrawingContext,
IUnknown* clientDrawingEffect,
float x,
float y,
float width,
float thickness,
DWRITE_READING_DIRECTION readingDirection,
DWRITE_FLOW_DIRECTION flowDirection) noexcept;
[[nodiscard]] HRESULT _DrawBasicGlyphRun(DrawingContext* clientDrawingContext,
D2D1_POINT_2F baselineOrigin,
@ -101,12 +101,12 @@ namespace Microsoft::Console::Render
D2D1_POINT_2F baselineOrigin,
DWRITE_MEASURING_MODE measuringMode,
_In_ const DWRITE_GLYPH_RUN* glyphRun,
_In_ const DWRITE_GLYPH_RUN_DESCRIPTION* glyphRunDescription);
_In_ const DWRITE_GLYPH_RUN_DESCRIPTION* glyphRunDescription) noexcept;
[[nodiscard]] HRESULT _DrawGlowGlyphRun(DrawingContext* clientDrawingContext,
D2D1_POINT_2F baselineOrigin,
DWRITE_MEASURING_MODE measuringMode,
_In_ const DWRITE_GLYPH_RUN* glyphRun,
_In_ const DWRITE_GLYPH_RUN_DESCRIPTION* glyphRunDescription);
_In_ const DWRITE_GLYPH_RUN_DESCRIPTION* glyphRunDescription) noexcept;
};
}

View file

@ -15,7 +15,7 @@
#pragma hdrstop
static constexpr float POINTS_PER_INCH = 72.0f;
static std::wstring FALLBACK_FONT_FACE = L"Consolas";
static constexpr std::wstring_view FALLBACK_FONT_FACE = L"Consolas";
static constexpr std::wstring_view FALLBACK_LOCALE = L"en-us";
using namespace Microsoft::Console::Render;
@ -24,6 +24,8 @@ using namespace Microsoft::Console::Types;
// Routine Description:
// - Constructs a DirectX-based renderer for console text
// which primarily uses DirectWrite on a Direct2D surface
#pragma warning(suppress : 26455)
// TODO GH 2683: The default constructor should not throw.
DxEngine::DxEngine() :
RenderEngineBase(),
_isInvalidUsed{ false },
@ -129,7 +131,7 @@ DxEngine::~DxEngine()
_ReleaseDeviceResources();
}
auto freeOnFail = wil::scope_exit([&] { _ReleaseDeviceResources(); });
auto freeOnFail = wil::scope_exit([&]() noexcept { _ReleaseDeviceResources(); });
RETURN_IF_FAILED(CreateDXGIFactory1(IID_PPV_ARGS(&_dxgiFactory2)));
@ -147,39 +149,37 @@ DxEngine::~DxEngine()
// D3D11_CREATE_DEVICE_DEBUG |
D3D11_CREATE_DEVICE_SINGLETHREADED;
D3D_FEATURE_LEVEL FeatureLevels[] = {
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_1,
};
const std::array<D3D_FEATURE_LEVEL, 5> FeatureLevels{ D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_1 };
// Trying hardware first for maximum performance, then trying WARP (software) renderer second
// in case we're running inside a downlevel VM where hardware passthrough isn't enabled like
// for Windows 7 in a VM.
const auto hardwareResult = D3D11CreateDevice(NULL,
const auto hardwareResult = D3D11CreateDevice(nullptr,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
nullptr,
DeviceFlags,
FeatureLevels,
ARRAYSIZE(FeatureLevels),
FeatureLevels.data(),
gsl::narrow_cast<UINT>(FeatureLevels.size()),
D3D11_SDK_VERSION,
&_d3dDevice,
NULL,
nullptr,
&_d3dDeviceContext);
if (FAILED(hardwareResult))
{
RETURN_IF_FAILED(D3D11CreateDevice(NULL,
RETURN_IF_FAILED(D3D11CreateDevice(nullptr,
D3D_DRIVER_TYPE_WARP,
NULL,
nullptr,
DeviceFlags,
FeatureLevels,
ARRAYSIZE(FeatureLevels),
FeatureLevels.data(),
gsl::narrow_cast<UINT>(FeatureLevels.size()),
D3D11_SDK_VERSION,
&_d3dDevice,
NULL,
nullptr,
&_d3dDeviceContext));
}
@ -196,58 +196,62 @@ DxEngine::~DxEngine()
SwapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
SwapChainDesc.Scaling = DXGI_SCALING_NONE;
switch (_chainMode)
try
{
case SwapChainMode::ForHwnd:
{
// use the HWND's dimensions for the swap chain dimensions.
RECT rect = { 0 };
RETURN_IF_WIN32_BOOL_FALSE(GetClientRect(_hwndTarget, &rect));
SwapChainDesc.Width = rect.right - rect.left;
SwapChainDesc.Height = rect.bottom - rect.top;
// We can't do alpha for HWNDs. Set to ignore. It will fail otherwise.
SwapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
const auto createSwapChainResult = _dxgiFactory2->CreateSwapChainForHwnd(_d3dDevice.Get(),
_hwndTarget,
&SwapChainDesc,
nullptr,
nullptr,
&_dxgiSwapChain);
if (FAILED(createSwapChainResult))
switch (_chainMode)
{
SwapChainDesc.Scaling = DXGI_SCALING_STRETCH;
RETURN_IF_FAILED(_dxgiFactory2->CreateSwapChainForHwnd(_d3dDevice.Get(),
_hwndTarget,
&SwapChainDesc,
nullptr,
nullptr,
&_dxgiSwapChain));
case SwapChainMode::ForHwnd:
{
// use the HWND's dimensions for the swap chain dimensions.
RECT rect = { 0 };
RETURN_IF_WIN32_BOOL_FALSE(GetClientRect(_hwndTarget, &rect));
SwapChainDesc.Width = rect.right - rect.left;
SwapChainDesc.Height = rect.bottom - rect.top;
// We can't do alpha for HWNDs. Set to ignore. It will fail otherwise.
SwapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
const auto createSwapChainResult = _dxgiFactory2->CreateSwapChainForHwnd(_d3dDevice.Get(),
_hwndTarget,
&SwapChainDesc,
nullptr,
nullptr,
&_dxgiSwapChain);
if (FAILED(createSwapChainResult))
{
SwapChainDesc.Scaling = DXGI_SCALING_STRETCH;
RETURN_IF_FAILED(_dxgiFactory2->CreateSwapChainForHwnd(_d3dDevice.Get(),
_hwndTarget,
&SwapChainDesc,
nullptr,
nullptr,
&_dxgiSwapChain));
}
break;
}
case SwapChainMode::ForComposition:
{
// Use the given target size for compositions.
SwapChainDesc.Width = _displaySizePixels.cx;
SwapChainDesc.Height = _displaySizePixels.cy;
break;
}
case SwapChainMode::ForComposition:
{
// Use the given target size for compositions.
SwapChainDesc.Width = _displaySizePixels.cx;
SwapChainDesc.Height = _displaySizePixels.cy;
// We're doing advanced composition pretty much for the purpose of pretty alpha, so turn it on.
SwapChainDesc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
// It's 100% required to use scaling mode stretch for composition. There is no other choice.
SwapChainDesc.Scaling = DXGI_SCALING_STRETCH;
// We're doing advanced composition pretty much for the purpose of pretty alpha, so turn it on.
SwapChainDesc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
// It's 100% required to use scaling mode stretch for composition. There is no other choice.
SwapChainDesc.Scaling = DXGI_SCALING_STRETCH;
RETURN_IF_FAILED(_dxgiFactory2->CreateSwapChainForComposition(_d3dDevice.Get(),
&SwapChainDesc,
nullptr,
&_dxgiSwapChain));
break;
}
default:
THROW_HR(E_NOTIMPL);
RETURN_IF_FAILED(_dxgiFactory2->CreateSwapChainForComposition(_d3dDevice.Get(),
&SwapChainDesc,
nullptr,
&_dxgiSwapChain));
break;
}
default:
THROW_HR(E_NOTIMPL);
}
}
CATCH_RETURN();
// With a new swap chain, mark the entire thing as invalid.
RETURN_IF_FAILED(InvalidateAll());
@ -265,9 +269,14 @@ DxEngine::~DxEngine()
freeOnFail.release(); // don't need to release if we made it to the bottom and everything was good.
// Notify that swap chain changed.
if (_pfn)
{
_pfn();
try
{
_pfn();
}
CATCH_LOG(); // A failure in the notification function isn't a failure to prepare, so just log it and go on.
}
return S_OK;
@ -275,54 +284,57 @@ DxEngine::~DxEngine()
[[nodiscard]] HRESULT DxEngine::_PrepareRenderTarget() noexcept
{
RETURN_IF_FAILED(_dxgiSwapChain->GetBuffer(0, IID_PPV_ARGS(&_dxgiSurface)));
D2D1_RENDER_TARGET_PROPERTIES props =
D2D1::RenderTargetProperties(
D2D1_RENDER_TARGET_TYPE_DEFAULT,
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
0.0f,
0.0f);
RETURN_IF_FAILED(_d2dFactory->CreateDxgiSurfaceRenderTarget(_dxgiSurface.Get(),
&props,
&_d2dRenderTarget));
_d2dRenderTarget->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE);
RETURN_IF_FAILED(_d2dRenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::DarkRed),
&_d2dBrushBackground));
RETURN_IF_FAILED(_d2dRenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White),
&_d2dBrushForeground));
const D2D1_STROKE_STYLE_PROPERTIES strokeStyleProperties{
D2D1_CAP_STYLE_SQUARE, // startCap
D2D1_CAP_STYLE_SQUARE, // endCap
D2D1_CAP_STYLE_SQUARE, // dashCap
D2D1_LINE_JOIN_MITER, // lineJoin
0.f, // miterLimit
D2D1_DASH_STYLE_SOLID, // dashStyle
0.f, // dashOffset
};
RETURN_IF_FAILED(_d2dFactory->CreateStrokeStyle(&strokeStyleProperties, nullptr, 0, &_strokeStyle));
// If in composition mode, apply scaling factor matrix
if (_chainMode == SwapChainMode::ForComposition)
try
{
const auto fdpi = static_cast<float>(_dpi);
_d2dRenderTarget->SetDpi(fdpi, fdpi);
RETURN_IF_FAILED(_dxgiSwapChain->GetBuffer(0, IID_PPV_ARGS(&_dxgiSurface)));
DXGI_MATRIX_3X2_F inverseScale = { 0 };
inverseScale._11 = 1.0f / _scale;
inverseScale._22 = inverseScale._11;
const D2D1_RENDER_TARGET_PROPERTIES props =
D2D1::RenderTargetProperties(
D2D1_RENDER_TARGET_TYPE_DEFAULT,
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
0.0f,
0.0f);
::Microsoft::WRL::ComPtr<IDXGISwapChain2> sc2;
RETURN_IF_FAILED(_dxgiSwapChain.As(&sc2));
RETURN_IF_FAILED(_d2dFactory->CreateDxgiSurfaceRenderTarget(_dxgiSurface.Get(),
&props,
&_d2dRenderTarget));
RETURN_IF_FAILED(sc2->SetMatrixTransform(&inverseScale));
_d2dRenderTarget->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE);
RETURN_IF_FAILED(_d2dRenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::DarkRed),
&_d2dBrushBackground));
RETURN_IF_FAILED(_d2dRenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White),
&_d2dBrushForeground));
const D2D1_STROKE_STYLE_PROPERTIES strokeStyleProperties{
D2D1_CAP_STYLE_SQUARE, // startCap
D2D1_CAP_STYLE_SQUARE, // endCap
D2D1_CAP_STYLE_SQUARE, // dashCap
D2D1_LINE_JOIN_MITER, // lineJoin
0.f, // miterLimit
D2D1_DASH_STYLE_SOLID, // dashStyle
0.f, // dashOffset
};
RETURN_IF_FAILED(_d2dFactory->CreateStrokeStyle(&strokeStyleProperties, nullptr, 0, &_strokeStyle));
// If in composition mode, apply scaling factor matrix
if (_chainMode == SwapChainMode::ForComposition)
{
const auto fdpi = static_cast<float>(_dpi);
_d2dRenderTarget->SetDpi(fdpi, fdpi);
DXGI_MATRIX_3X2_F inverseScale = { 0 };
inverseScale._11 = 1.0f / _scale;
inverseScale._22 = inverseScale._11;
::Microsoft::WRL::ComPtr<IDXGISwapChain2> sc2;
RETURN_IF_FAILED(_dxgiSwapChain.As(&sc2));
RETURN_IF_FAILED(sc2->SetMatrixTransform(&inverseScale));
}
return S_OK;
}
return S_OK;
CATCH_RETURN();
}
// Routine Description:
@ -333,31 +345,35 @@ DxEngine::~DxEngine()
// - <none>
void DxEngine::_ReleaseDeviceResources() noexcept
{
_haveDeviceResources = false;
_d2dBrushForeground.Reset();
_d2dBrushBackground.Reset();
if (nullptr != _d2dRenderTarget.Get() && _isPainting)
try
{
_d2dRenderTarget->EndDraw();
_haveDeviceResources = false;
_d2dBrushForeground.Reset();
_d2dBrushBackground.Reset();
if (nullptr != _d2dRenderTarget.Get() && _isPainting)
{
_d2dRenderTarget->EndDraw();
}
_d2dRenderTarget.Reset();
_dxgiSurface.Reset();
_dxgiSwapChain.Reset();
if (nullptr != _d3dDeviceContext.Get())
{
// To ensure the swap chain goes away we must unbind any views from the
// D3D pipeline
_d3dDeviceContext->OMSetRenderTargets(0, nullptr, nullptr);
}
_d3dDeviceContext.Reset();
_d3dDevice.Reset();
_dxgiFactory2.Reset();
}
_d2dRenderTarget.Reset();
_dxgiSurface.Reset();
_dxgiSwapChain.Reset();
if (nullptr != _d3dDeviceContext.Get())
{
// To ensure the swap chain goes away we must unbind any views from the
// D3D pipeline
_d3dDeviceContext->OMSetRenderTargets(0, nullptr, nullptr);
}
_d3dDeviceContext.Reset();
_d3dDevice.Reset();
_dxgiFactory2.Reset();
CATCH_LOG();
}
// Routine Description:
@ -375,10 +391,10 @@ void DxEngine::_ReleaseDeviceResources() noexcept
_Out_ IDWriteTextLayout** ppTextLayout) noexcept
{
return _dwriteFactory->CreateTextLayout(string,
static_cast<UINT32>(stringLength),
gsl::narrow<UINT32>(stringLength),
_dwriteTextFormat.Get(),
(float)_displaySizePixels.cx,
_glyphCell.cy != 0 ? _glyphCell.cy : (float)_displaySizePixels.cy,
gsl::narrow<float>(_displaySizePixels.cx),
_glyphCell.cy != 0 ? _glyphCell.cy : gsl::narrow<float>(_displaySizePixels.cy),
ppTextLayout);
}
@ -410,7 +426,7 @@ void DxEngine::SetCallback(std::function<void()> pfn)
_pfn = pfn;
}
Microsoft::WRL::ComPtr<IDXGISwapChain1> DxEngine::GetSwapChain() noexcept
Microsoft::WRL::ComPtr<IDXGISwapChain1> DxEngine::GetSwapChain()
{
if (_dxgiSwapChain.Get() == nullptr)
{
@ -428,6 +444,8 @@ Microsoft::WRL::ComPtr<IDXGISwapChain1> DxEngine::GetSwapChain() noexcept
// - S_OK
[[nodiscard]] HRESULT DxEngine::Invalidate(const SMALL_RECT* const psrRegion) noexcept
{
RETURN_HR_IF_NULL(E_INVALIDARG, psrRegion);
_InvalidOr(*psrRegion);
return S_OK;
}
@ -440,7 +458,9 @@ Microsoft::WRL::ComPtr<IDXGISwapChain1> DxEngine::GetSwapChain() noexcept
// - S_OK
[[nodiscard]] HRESULT DxEngine::InvalidateCursor(const COORD* const pcoordCursor) noexcept
{
SMALL_RECT sr = Microsoft::Console::Types::Viewport::FromCoord(*pcoordCursor).ToInclusive();
RETURN_HR_IF_NULL(E_INVALIDARG, pcoordCursor);
const SMALL_RECT sr = Microsoft::Console::Types::Viewport::FromCoord(*pcoordCursor).ToInclusive();
return Invalidate(&sr);
}
@ -452,6 +472,8 @@ Microsoft::WRL::ComPtr<IDXGISwapChain1> DxEngine::GetSwapChain() noexcept
// - S_OK
[[nodiscard]] HRESULT DxEngine::InvalidateSystem(const RECT* const prcDirtyClient) noexcept
{
RETURN_HR_IF_NULL(E_INVALIDARG, prcDirtyClient);
_InvalidOr(*prcDirtyClient);
return S_OK;
@ -484,39 +506,43 @@ Microsoft::WRL::ComPtr<IDXGISwapChain1> DxEngine::GetSwapChain() noexcept
{
if (pcoordDelta->X != 0 || pcoordDelta->Y != 0)
{
POINT delta = { 0 };
delta.x = pcoordDelta->X * _glyphCell.cx;
delta.y = pcoordDelta->Y * _glyphCell.cy;
_InvalidOffset(delta);
_invalidScroll.cx += delta.x;
_invalidScroll.cy += delta.y;
// Add the revealed portion of the screen from the scroll to the invalid area.
const RECT display = _GetDisplayRect();
RECT reveal = display;
// X delta first
OffsetRect(&reveal, delta.x, 0);
IntersectRect(&reveal, &reveal, &display);
SubtractRect(&reveal, &display, &reveal);
if (!IsRectEmpty(&reveal))
try
{
_InvalidOr(reveal);
}
POINT delta = { 0 };
delta.x = pcoordDelta->X * _glyphCell.cx;
delta.y = pcoordDelta->Y * _glyphCell.cy;
// Y delta second (subtract rect won't work if you move both)
reveal = display;
OffsetRect(&reveal, 0, delta.y);
IntersectRect(&reveal, &reveal, &display);
SubtractRect(&reveal, &display, &reveal);
_InvalidOffset(delta);
if (!IsRectEmpty(&reveal))
{
_InvalidOr(reveal);
_invalidScroll.cx += delta.x;
_invalidScroll.cy += delta.y;
// Add the revealed portion of the screen from the scroll to the invalid area.
const RECT display = _GetDisplayRect();
RECT reveal = display;
// X delta first
OffsetRect(&reveal, delta.x, 0);
IntersectRect(&reveal, &reveal, &display);
SubtractRect(&reveal, &display, &reveal);
if (!IsRectEmpty(&reveal))
{
_InvalidOr(reveal);
}
// Y delta second (subtract rect won't work if you move both)
reveal = display;
OffsetRect(&reveal, 0, delta.y);
IntersectRect(&reveal, &reveal, &display);
SubtractRect(&reveal, &display, &reveal);
if (!IsRectEmpty(&reveal))
{
_InvalidOr(reveal);
}
}
CATCH_RETURN();
}
return S_OK;
@ -544,6 +570,8 @@ Microsoft::WRL::ComPtr<IDXGISwapChain1> DxEngine::GetSwapChain() noexcept
// - S_FALSE because we don't use this.
[[nodiscard]] HRESULT DxEngine::InvalidateCircling(_Out_ bool* const pForcePaint) noexcept
{
RETURN_HR_IF_NULL(E_INVALIDARG, pForcePaint);
*pForcePaint = false;
return S_FALSE;
}
@ -577,7 +605,7 @@ Microsoft::WRL::ComPtr<IDXGISwapChain1> DxEngine::GetSwapChain() noexcept
return size;
}
default:
THROW_HR(E_NOTIMPL);
FAIL_FAST_HR(E_NOTIMPL);
}
}
@ -617,7 +645,7 @@ void _ScaleByFont(RECT& cellsToPixels, SIZE fontSize) noexcept
// - -Y is up, Y is down, -X is left, X is right.
// Return Value:
// - <none>
void DxEngine::_InvalidOffset(POINT delta) noexcept
void DxEngine::_InvalidOffset(POINT delta)
{
if (_isInvalidUsed)
{
@ -671,7 +699,7 @@ void DxEngine::_InvalidOr(RECT rc) noexcept
{
UnionRect(&_invalidRect, &_invalidRect, &rc);
RECT rcScreen = _GetDisplayRect();
const RECT rcScreen = _GetDisplayRect();
IntersectRect(&_invalidRect, &_invalidRect, &rcScreen);
}
else
@ -689,6 +717,8 @@ void DxEngine::_InvalidOr(RECT rc) noexcept
// - S_FALSE because this is unused.
[[nodiscard]] HRESULT DxEngine::PrepareForTeardown(_Out_ bool* const pForcePaint) noexcept
{
RETURN_HR_IF_NULL(E_INVALIDARG, pForcePaint);
*pForcePaint = false;
return S_FALSE;
}
@ -706,37 +736,41 @@ void DxEngine::_InvalidOr(RECT rc) noexcept
if (_isEnabled)
{
const auto clientSize = _GetClientSize();
if (!_haveDeviceResources)
try
{
RETURN_IF_FAILED(_CreateDeviceResources(true));
const auto clientSize = _GetClientSize();
if (!_haveDeviceResources)
{
RETURN_IF_FAILED(_CreateDeviceResources(true));
}
else if (_displaySizePixels.cy != clientSize.cy ||
_displaySizePixels.cx != clientSize.cx)
{
// OK, we're going to play a dangerous game here for the sake of optimizing resize
// First, set up a complete clear of all device resources if something goes terribly wrong.
auto resetDeviceResourcesOnFailure = wil::scope_exit([&]() noexcept {
_ReleaseDeviceResources();
});
// Now let go of a few of the device resources that get in the way of resizing buffers in the swap chain
_dxgiSurface.Reset();
_d2dRenderTarget.Reset();
// Change the buffer size and recreate the render target (and surface)
RETURN_IF_FAILED(_dxgiSwapChain->ResizeBuffers(2, clientSize.cx, clientSize.cy, DXGI_FORMAT_B8G8R8A8_UNORM, 0));
RETURN_IF_FAILED(_PrepareRenderTarget());
// OK we made it past the parts that can cause errors. We can release our failure handler.
resetDeviceResourcesOnFailure.release();
// And persist the new size.
_displaySizePixels = clientSize;
}
_d2dRenderTarget->BeginDraw();
_isPainting = true;
}
else if (_displaySizePixels.cy != clientSize.cy ||
_displaySizePixels.cx != clientSize.cx)
{
// OK, we're going to play a dangerous game here for the sake of optimizing resize
// First, set up a complete clear of all device resources if something goes terribly wrong.
auto resetDeviceResourcesOnFailure = wil::scope_exit([&] {
_ReleaseDeviceResources();
});
// Now let go of a few of the device resources that get in the way of resizing buffers in the swap chain
_dxgiSurface.Reset();
_d2dRenderTarget.Reset();
// Change the buffer size and recreate the render target (and surface)
RETURN_IF_FAILED(_dxgiSwapChain->ResizeBuffers(2, clientSize.cx, clientSize.cy, DXGI_FORMAT_B8G8R8A8_UNORM, 0));
RETURN_IF_FAILED(_PrepareRenderTarget());
// OK we made it past the parts that can cause errors. We can release our failure handler.
resetDeviceResourcesOnFailure.release();
// And persist the new size.
_displaySizePixels = clientSize;
}
_d2dRenderTarget->BeginDraw();
_isPainting = true;
CATCH_RETURN();
}
return S_OK;
@ -766,7 +800,7 @@ void DxEngine::_InvalidOr(RECT rc) noexcept
{
_presentDirty = _invalidRect;
RECT display = _GetDisplayRect();
const RECT display = _GetDisplayRect();
SubtractRect(&_presentScroll, &display, &_presentDirty);
_presentOffset.x = _invalidScroll.cx;
_presentOffset.y = _invalidScroll.cy;
@ -811,13 +845,17 @@ void DxEngine::_InvalidOr(RECT rc) noexcept
// - Any DirectX error, a memory error, etc.
[[nodiscard]] HRESULT DxEngine::_CopyFrontToBack() noexcept
{
Microsoft::WRL::ComPtr<ID3D11Resource> backBuffer;
Microsoft::WRL::ComPtr<ID3D11Resource> frontBuffer;
try
{
Microsoft::WRL::ComPtr<ID3D11Resource> backBuffer;
Microsoft::WRL::ComPtr<ID3D11Resource> frontBuffer;
RETURN_IF_FAILED(_dxgiSwapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer)));
RETURN_IF_FAILED(_dxgiSwapChain->GetBuffer(1, IID_PPV_ARGS(&frontBuffer)));
RETURN_IF_FAILED(_dxgiSwapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer)));
RETURN_IF_FAILED(_dxgiSwapChain->GetBuffer(1, IID_PPV_ARGS(&frontBuffer)));
_d3dDeviceContext->CopyResource(backBuffer.Get(), frontBuffer.Get());
_d3dDeviceContext->CopyResource(backBuffer.Get(), frontBuffer.Get());
}
CATCH_RETURN();
return S_OK;
}
@ -833,16 +871,20 @@ void DxEngine::_InvalidOr(RECT rc) noexcept
{
if (_presentReady)
{
FAIL_FAST_IF_FAILED(_dxgiSwapChain->Present(1, 0));
/*FAIL_FAST_IF_FAILED(_dxgiSwapChain->Present1(1, 0, &_presentParams));*/
try
{
FAIL_FAST_IF_FAILED(_dxgiSwapChain->Present(1, 0));
/*FAIL_FAST_IF_FAILED(_dxgiSwapChain->Present1(1, 0, &_presentParams));*/
RETURN_IF_FAILED(_CopyFrontToBack());
_presentReady = false;
RETURN_IF_FAILED(_CopyFrontToBack());
_presentReady = false;
_presentDirty = { 0 };
_presentOffset = { 0 };
_presentScroll = { 0 };
_presentParams = { 0 };
_presentDirty = { 0 };
_presentOffset = { 0 };
_presentScroll = { 0 };
_presentParams = { 0 };
}
CATCH_RETURN();
}
return S_OK;
@ -945,7 +987,7 @@ void DxEngine::_InvalidOr(RECT rc) noexcept
COORD const coordTarget) noexcept
{
const auto existingColor = _d2dBrushForeground->GetColor();
const auto restoreBrushOnExit = wil::scope_exit([&] { _d2dBrushForeground->SetColor(existingColor); });
const auto restoreBrushOnExit = wil::scope_exit([&]() noexcept { _d2dBrushForeground->SetColor(existingColor); });
_d2dBrushForeground->SetColor(_ColorFFromColorRef(color));
@ -1028,7 +1070,7 @@ void DxEngine::_InvalidOr(RECT rc) noexcept
0.5f);
_d2dBrushForeground->SetColor(selectionColor);
const auto resetColorOnExit = wil::scope_exit([&] { _d2dBrushForeground->SetColor(existingColor); });
const auto resetColorOnExit = wil::scope_exit([&]() noexcept { _d2dBrushForeground->SetColor(existingColor); });
RECT pixels;
pixels.left = rect.Left * _glyphCell.cx;
@ -1089,7 +1131,8 @@ enum class CursorPaintType
{
// Enforce min/max cursor height
ULONG ulHeight = std::clamp(options.ulCursorHeightPercent, s_ulMinCursorHeightPercent, s_ulMaxCursorHeightPercent);
ulHeight = (ULONG)((_glyphCell.cy * ulHeight) / 100);
ulHeight = gsl::narrow<ULONG>((_glyphCell.cy * ulHeight) / 100);
rect.top = rect.bottom - ulHeight;
break;
}
@ -1202,25 +1245,29 @@ enum class CursorPaintType
// - S_OK or relevant DirectX error
[[nodiscard]] HRESULT DxEngine::UpdateFont(const FontInfoDesired& pfiFontInfoDesired, FontInfo& fiFontInfo) noexcept
{
const auto hr = _GetProposedFont(pfiFontInfoDesired,
fiFontInfo,
_dpi,
_dwriteTextFormat,
_dwriteTextAnalyzer,
_dwriteFontFace);
RETURN_IF_FAILED(_GetProposedFont(pfiFontInfoDesired,
fiFontInfo,
_dpi,
_dwriteTextFormat,
_dwriteTextAnalyzer,
_dwriteFontFace));
const auto size = fiFontInfo.GetSize();
try
{
const auto size = fiFontInfo.GetSize();
_glyphCell.cx = size.X;
_glyphCell.cy = size.Y;
_glyphCell.cx = size.X;
_glyphCell.cy = size.Y;
}
CATCH_RETURN();
return hr;
return S_OK;
}
[[nodiscard]] Viewport DxEngine::GetViewportInCharacters(const Viewport& viewInPixels) noexcept
{
short widthInChars = static_cast<short>(viewInPixels.Width() / _glyphCell.cx);
short heightInChars = static_cast<short>(viewInPixels.Height() / _glyphCell.cy);
const short widthInChars = gsl::narrow_cast<short>(viewInPixels.Width() / _glyphCell.cx);
const short heightInChars = gsl::narrow_cast<short>(viewInPixels.Height() / _glyphCell.cy);
return Viewport::FromDimensions(viewInPixels.Origin(), { widthInChars, heightInChars });
}
@ -1297,13 +1344,13 @@ float DxEngine::GetScaling() const noexcept
// - <none>
// Return Value:
// - Rectangle describing dirty area in characters.
[[nodiscard]] SMALL_RECT DxEngine::GetDirtyRectInChars() noexcept
[[nodiscard]] SMALL_RECT DxEngine::GetDirtyRectInChars()
{
SMALL_RECT r;
r.Top = (SHORT)(floor(_invalidRect.top / _glyphCell.cy));
r.Left = (SHORT)(floor(_invalidRect.left / _glyphCell.cx));
r.Bottom = (SHORT)(floor(_invalidRect.bottom / _glyphCell.cy));
r.Right = (SHORT)(floor(_invalidRect.right / _glyphCell.cx));
r.Top = gsl::narrow<SHORT>(floor(_invalidRect.top / _glyphCell.cy));
r.Left = gsl::narrow<SHORT>(floor(_invalidRect.left / _glyphCell.cx));
r.Bottom = gsl::narrow<SHORT>(floor(_invalidRect.bottom / _glyphCell.cy));
r.Right = gsl::narrow<SHORT>(floor(_invalidRect.right / _glyphCell.cx));
// Exclusive to inclusive
r.Bottom--;
@ -1321,7 +1368,7 @@ float DxEngine::GetScaling() const noexcept
// - Nearest integer short x and y values for each cell.
[[nodiscard]] COORD DxEngine::_GetFontSize() const noexcept
{
return { (SHORT)(_glyphCell.cx), (SHORT)(_glyphCell.cy) };
return { gsl::narrow<SHORT>(_glyphCell.cx), gsl::narrow<SHORT>(_glyphCell.cy) };
}
// Routine Description:
@ -1345,20 +1392,26 @@ float DxEngine::GetScaling() const noexcept
// - S_OK or relevant DirectWrite error.
[[nodiscard]] HRESULT DxEngine::IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept
{
Cluster cluster(glyph, 0); // columns don't matter, we're doing analysis not layout.
RETURN_HR_IF_NULL(E_INVALIDARG, pResult);
// Create the text layout
CustomTextLayout layout(_dwriteFactory.Get(),
_dwriteTextAnalyzer.Get(),
_dwriteTextFormat.Get(),
_dwriteFontFace.Get(),
{ &cluster, 1 },
_glyphCell.cx);
try
{
const Cluster cluster(glyph, 0); // columns don't matter, we're doing analysis not layout.
UINT32 columns = 0;
RETURN_IF_FAILED(layout.GetColumns(&columns));
// Create the text layout
CustomTextLayout layout(_dwriteFactory.Get(),
_dwriteTextAnalyzer.Get(),
_dwriteTextFormat.Get(),
_dwriteFontFace.Get(),
{ &cluster, 1 },
_glyphCell.cx);
*pResult = columns != 1;
UINT32 columns = 0;
RETURN_IF_FAILED(layout.GetColumns(&columns));
*pResult = columns != 1;
}
CATCH_RETURN();
return S_OK;
}
@ -1371,7 +1424,7 @@ float DxEngine::GetScaling() const noexcept
// - S_OK
[[nodiscard]] HRESULT DxEngine::_DoUpdateTitle(_In_ const std::wstring& /*newTitle*/) noexcept
{
return PostMessageW(_hwndTarget, CM_UPDATE_TITLE, 0, (LPARAM) nullptr) ? S_OK : E_FAIL;
return PostMessageW(_hwndTarget, CM_UPDATE_TITLE, 0, 0) ? S_OK : E_FAIL;
}
// Routine Description:
@ -1451,6 +1504,11 @@ float DxEngine::GetScaling() const noexcept
THROW_IF_FAILED(fontFace0.As(&fontFace));
// Retrieve metrics in case the font we created was different than what was requested.
weight = font->GetWeight();
stretch = font->GetStretch();
style = font->GetStyle();
// Dig the family name out at the end to return it.
familyName = _GetFontFamilyName(fontFamily.Get(), localeName);
}
@ -1488,7 +1546,7 @@ float DxEngine::GetScaling() const noexcept
// - If fallback occurred, this is updated to what we retrieved instead.
// Return Value:
// - Localized string name of the font family
[[nodiscard]] std::wstring DxEngine::_GetFontFamilyName(IDWriteFontFamily* const fontFamily,
[[nodiscard]] std::wstring DxEngine::_GetFontFamilyName(gsl::not_null<IDWriteFontFamily*> const fontFamily,
std::wstring& localeName) const
{
// See: https://docs.microsoft.com/en-us/windows/win32/api/dwrite/nn-dwrite-idwritefontcollection
@ -1691,9 +1749,9 @@ float DxEngine::GetScaling() const noexcept
// Unscaled is for the purposes of re-communicating this font back to the renderer again later.
// As such, we need to give the same original size parameter back here without padding
// or rounding or scaling manipulation.
COORD unscaled = desired.GetEngineSize();
const COORD unscaled = desired.GetEngineSize();
COORD scaled = coordSize;
const COORD scaled = coordSize;
actual.SetFromEngine(fontName.data(),
desired.GetFamily(),
@ -1733,22 +1791,6 @@ float DxEngine::GetScaling() const noexcept
return D2D1::ColorF(rgb, aFloat);
}
default:
THROW_HR(E_NOTIMPL);
FAIL_FAST_HR(E_NOTIMPL);
}
}
// Routine Description:
// - Helps convert a Direct2D ColorF into a DXGI RGBA
// Arguments:
// - color - Direct2D Color F
// Return Value:
// - DXGI RGBA
[[nodiscard]] DXGI_RGBA DxEngine::s_RgbaFromColorF(const D2D1_COLOR_F color) noexcept
{
DXGI_RGBA rgba;
rgba.a = color.a;
rgba.b = color.b;
rgba.g = color.g;
rgba.r = color.r;
return rgba;
}

View file

@ -31,7 +31,11 @@ namespace Microsoft::Console::Render
{
public:
DxEngine();
virtual ~DxEngine() override;
~DxEngine();
DxEngine(const DxEngine&) = default;
DxEngine(DxEngine&&) = default;
DxEngine& operator=(const DxEngine&) = default;
DxEngine& operator=(DxEngine&&) = default;
// Used to release device resources so that another instance of
// conhost can render to the screen (i.e. only one DirectX
@ -45,7 +49,7 @@ namespace Microsoft::Console::Render
void SetCallback(std::function<void()> pfn);
::Microsoft::WRL::ComPtr<IDXGISwapChain1> GetSwapChain() noexcept;
::Microsoft::WRL::ComPtr<IDXGISwapChain1> GetSwapChain();
// IRenderEngine Members
[[nodiscard]] HRESULT Invalidate(const SMALL_RECT* const psrRegion) noexcept override;
@ -84,7 +88,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT GetProposedFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo, int const iDpi) noexcept override;
[[nodiscard]] SMALL_RECT GetDirtyRectInChars() noexcept override;
[[nodiscard]] SMALL_RECT GetDirtyRectInChars() override;
[[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) noexcept override;
[[nodiscard]] HRESULT IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept override;
@ -133,7 +137,7 @@ namespace Microsoft::Console::Render
void _InvalidOr(SMALL_RECT sr) noexcept;
void _InvalidOr(RECT rc) noexcept;
void _InvalidOffset(POINT pt) noexcept;
void _InvalidOffset(POINT pt);
bool _presentReady;
RECT _presentDirty;
@ -193,7 +197,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] std::wstring _GetLocaleName() const;
[[nodiscard]] std::wstring _GetFontFamilyName(IDWriteFontFamily* const fontFamily,
[[nodiscard]] std::wstring _GetFontFamilyName(gsl::not_null<IDWriteFontFamily*> const fontFamily,
std::wstring& localeName) const;
[[nodiscard]] HRESULT _GetProposedFont(const FontInfoDesired& desired,
@ -209,6 +213,15 @@ namespace Microsoft::Console::Render
[[nodiscard]] D2D1_COLOR_F _ColorFFromColorRef(const COLORREF color) noexcept;
[[nodiscard]] static DXGI_RGBA s_RgbaFromColorF(const D2D1_COLOR_F color) noexcept;
// Routine Description:
// - Helps convert a Direct2D ColorF into a DXGI RGBA
// Arguments:
// - color - Direct2D Color F
// Return Value:
// - DXGI RGBA
[[nodiscard]] constexpr DXGI_RGBA s_RgbaFromColorF(const D2D1_COLOR_F color) noexcept
{
return { color.r, color.g, color.b, color.a };
}
};
}

View file

@ -64,6 +64,14 @@ namespace Microsoft::Console::Render
virtual ~IRenderEngine() = 0;
protected:
IRenderEngine() = default;
IRenderEngine(const IRenderEngine&) = default;
IRenderEngine(IRenderEngine&&) = default;
IRenderEngine& operator=(const IRenderEngine&) = default;
IRenderEngine& operator=(IRenderEngine&&) = default;
public:
[[nodiscard]] virtual HRESULT StartPaint() noexcept = 0;
[[nodiscard]] virtual HRESULT EndPaint() noexcept = 0;
[[nodiscard]] virtual HRESULT Present() noexcept = 0;

View file

@ -25,6 +25,14 @@ namespace Microsoft::Console::Render
public:
virtual ~IRenderTarget() = 0;
protected:
IRenderTarget() = default;
IRenderTarget(const IRenderTarget&) = default;
IRenderTarget(IRenderTarget&&) = default;
IRenderTarget& operator=(const IRenderTarget&) = default;
IRenderTarget& operator=(IRenderTarget&&) = default;
public:
virtual void TriggerRedraw(const Microsoft::Console::Types::Viewport& region) = 0;
virtual void TriggerRedraw(const COORD* const pcoord) = 0;
virtual void TriggerRedrawCursor(const COORD* const pcoord) = 0;

View file

@ -24,9 +24,16 @@ namespace Microsoft::Console::Render
class RenderEngineBase : public IRenderEngine
{
public:
RenderEngineBase();
virtual ~RenderEngineBase() = 0;
~RenderEngineBase() = 0;
protected:
RenderEngineBase();
RenderEngineBase(const RenderEngineBase&) = default;
RenderEngineBase(RenderEngineBase&&) = default;
RenderEngineBase& operator=(const RenderEngineBase&) = default;
RenderEngineBase& operator=(RenderEngineBase&&) = default;
public:
[[nodiscard]] HRESULT InvalidateTitle(const std::wstring& proposedTitle) noexcept override;
[[nodiscard]] HRESULT UpdateTitle(const std::wstring& newTitle) noexcept override;

View file

@ -14,7 +14,7 @@ namespace
CodepointWidth width;
};
static bool operator<(const UnicodeRange& range, const unsigned int searchTerm)
static bool operator<(const UnicodeRange& range, const unsigned int searchTerm) noexcept
{
return range.upperBound < searchTerm;
}
@ -310,13 +310,21 @@ namespace
};
}
// Routine Description:
// - Constructs an instance of the CodepointWidthDetector class
CodepointWidthDetector::CodepointWidthDetector() noexcept :
_fallbackCache{},
_pfnFallbackMethod{}
{
}
// Routine Description:
// - returns the width type of codepoint by searching the map generated from the unicode spec
// Arguments:
// - glyph - the utf16 encoded codepoint to search for
// Return Value:
// - the width type of the codepoint
CodepointWidth CodepointWidthDetector::GetWidth(const std::wstring_view glyph) const noexcept
CodepointWidth CodepointWidthDetector::GetWidth(const std::wstring_view glyph) const
{
if (glyph.empty())
{
@ -443,7 +451,7 @@ bool CodepointWidthDetector::_checkFallbackViaCache(const std::wstring_view glyp
const std::wstring findMe{ glyph };
// TODO: Cache needs to be emptied when font changes.
auto it = _fallbackCache.find(findMe);
const auto it = _fallbackCache.find(findMe);
if (it == _fallbackCache.end())
{
auto result = _pfnFallbackMethod(glyph);

View file

@ -5,6 +5,8 @@
#include "inc/CodepointWidthDetector.hpp"
#include "inc/GlyphWidth.hpp"
#pragma warning(suppress : 26426)
// TODO GH 2676 - remove warning suppression and decide what to do re: singleton instance of CodepointWidthDetector
static CodepointWidthDetector widthDetector;
// Function Description:
@ -18,7 +20,7 @@ bool IsGlyphFullWidth(const std::wstring_view glyph)
// Function Description:
// - determines if the glyph represented by the single character should be
// wide or not. See CodepointWidthDetector::IsWide
bool IsGlyphFullWidth(const wchar_t wch)
bool IsGlyphFullWidth(const wchar_t wch) noexcept
{
return widthDetector.IsWide(wch);
}
@ -44,7 +46,7 @@ void SetGlyphWidthFallback(std::function<bool(const std::wstring_view)> pfnFallb
// - <none>
// Return Value:
// - <none>
void NotifyGlyphWidthFontChanged()
void NotifyGlyphWidthFontChanged() noexcept
{
widthDetector.NotifyFontChanged();
}

View file

@ -24,6 +24,15 @@ namespace Microsoft::Console::Types
{
public:
virtual ~IBaseData() = 0;
protected:
IBaseData() = default;
IBaseData(const IBaseData&) = default;
IBaseData(IBaseData&&) = default;
IBaseData& operator=(const IBaseData&) = default;
IBaseData& operator=(IBaseData&&) = default;
public:
virtual Microsoft::Console::Types::Viewport GetViewport() noexcept = 0;
virtual const TextBuffer& GetTextBuffer() noexcept = 0;
virtual const FontInfo& GetFontInfo() noexcept = 0;

View file

@ -48,7 +48,7 @@ std::deque<std::unique_ptr<IInputEvent>> IInputEvent::Create(const std::deque<IN
std::deque<std::unique_ptr<IInputEvent>> outEvents;
for (size_t i = 0; i < records.size(); ++i)
{
std::unique_ptr<IInputEvent> event = IInputEvent::Create(records[i]);
std::unique_ptr<IInputEvent> event = IInputEvent::Create(records.at(i));
outEvents.push_back(std::move(event));
}
return outEvents;

View file

@ -23,8 +23,16 @@ namespace Microsoft::Console::Types
class IUiaData : public IBaseData
{
public:
virtual ~IUiaData() = 0;
~IUiaData() = 0;
protected:
IUiaData() = default;
IUiaData(const IUiaData&) = default;
IUiaData(IUiaData&&) = default;
IUiaData& operator=(const IUiaData&) = default;
IUiaData& operator=(IUiaData&&) = default;
public:
virtual const bool IsSelectionActive() const = 0;
virtual void ClearSelection() = 0;
virtual void SelectNewRegion(const COORD coordStart, const COORD coordEnd) = 0;

View file

@ -68,7 +68,7 @@ void KeyEvent::ActivateModifierKey(const ModifierKeyState modifierKey) noexcept
WI_SetAllFlags(_activeModifierKeys, bitFlag);
}
bool KeyEvent::DoActiveModifierKeysMatch(const std::unordered_set<ModifierKeyState>& consoleModifiers) const noexcept
bool KeyEvent::DoActiveModifierKeysMatch(const std::unordered_set<ModifierKeyState>& consoleModifiers) const
{
DWORD consoleBits = 0;
for (const ModifierKeyState& mod : consoleModifiers)

View file

@ -10,14 +10,16 @@ using namespace Microsoft::Console::Types;
using namespace Microsoft::Console::Types::ScreenInfoUiaProviderTracing;
// A helper function to create a SafeArray Version of an int array of a specified length
SAFEARRAY* BuildIntSafeArray(_In_reads_(length) const int* const data, const int length)
SAFEARRAY* BuildIntSafeArray(std::basic_string_view<int> data)
{
SAFEARRAY* psa = SafeArrayCreateVector(VT_I4, 0, length);
SAFEARRAY* psa = SafeArrayCreateVector(VT_I4, 0, gsl::narrow<ULONG>(data.size()));
if (psa != nullptr)
{
for (long i = 0; i < length; i++)
for (size_t i = 0; i < data.size(); i++)
{
if (FAILED(SafeArrayPutElement(psa, &i, (void*)&(data[i]))))
LONG lIndex = 0;
if (FAILED(SizeTToLong(i, &lIndex) ||
FAILED(SafeArrayPutElement(psa, &lIndex, (void*)&(data.at(i))))))
{
SafeArrayDestroy(psa);
psa = nullptr;
@ -38,10 +40,6 @@ ScreenInfoUiaProviderBase::ScreenInfoUiaProviderBase(_In_ IUiaData* pData) :
//Tracing::s_TraceUia(nullptr, ApiCall::Constructor, nullptr);
}
ScreenInfoUiaProviderBase::~ScreenInfoUiaProviderBase()
{
}
[[nodiscard]] HRESULT ScreenInfoUiaProviderBase::Signal(_In_ EVENTID id)
{
HRESULT hr = S_OK;
@ -58,7 +56,7 @@ ScreenInfoUiaProviderBase::~ScreenInfoUiaProviderBase()
}
CATCH_RETURN();
IRawElementProviderSimple* pProvider = static_cast<IRawElementProviderSimple*>(this);
IRawElementProviderSimple* pProvider = this;
hr = UiaRaiseAutomationEvent(pProvider, id);
_signalFiringMapping[id] = false;
@ -85,7 +83,7 @@ ScreenInfoUiaProviderBase::Release()
{
// TODO GitHub #1914: Re-attach Tracing to UIA Tree
//Tracing::s_TraceUia(this, ApiCall::Release, nullptr);
long val = InterlockedDecrement(&_cRefs);
const long val = InterlockedDecrement(&_cRefs);
if (val == 0)
{
delete this;
@ -96,23 +94,16 @@ ScreenInfoUiaProviderBase::Release()
IFACEMETHODIMP ScreenInfoUiaProviderBase::QueryInterface(_In_ REFIID riid,
_COM_Outptr_result_maybenull_ void** ppInterface)
{
RETURN_HR_IF_NULL(E_INVALIDARG, ppInterface);
// TODO GitHub #1914: Re-attach Tracing to UIA Tree
//Tracing::s_TraceUia(this, ApiCall::QueryInterface, nullptr);
if (riid == __uuidof(IUnknown))
if (riid == __uuidof(IUnknown) ||
riid == __uuidof(IRawElementProviderSimple) ||
riid == __uuidof(IRawElementProviderFragment) ||
riid == __uuidof(ITextProvider))
{
*ppInterface = static_cast<IRawElementProviderSimple*>(this);
}
else if (riid == __uuidof(IRawElementProviderSimple))
{
*ppInterface = static_cast<IRawElementProviderSimple*>(this);
}
else if (riid == __uuidof(IRawElementProviderFragment))
{
*ppInterface = static_cast<IRawElementProviderFragment*>(this);
}
else if (riid == __uuidof(ITextProvider))
{
*ppInterface = static_cast<ITextProvider*>(this);
*ppInterface = this;
}
else
{
@ -120,7 +111,7 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::QueryInterface(_In_ REFIID riid,
return E_NOINTERFACE;
}
(static_cast<IUnknown*>(*ppInterface))->AddRef();
AddRef();
return S_OK;
}
@ -131,8 +122,10 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::QueryInterface(_In_ REFIID riid,
// Implementation of IRawElementProviderSimple::get_ProviderOptions.
// Gets UI Automation provider options.
IFACEMETHODIMP ScreenInfoUiaProviderBase::get_ProviderOptions(_Out_ ProviderOptions* pOptions)
IFACEMETHODIMP ScreenInfoUiaProviderBase::get_ProviderOptions(_Out_ ProviderOptions* pOptions) noexcept
{
RETURN_HR_IF_NULL(E_INVALIDARG, pOptions);
// TODO GitHub #1914: Re-attach Tracing to UIA Tree
//Tracing::s_TraceUia(this, ApiCall::GetProviderOptions, nullptr);
*pOptions = ProviderOptions_ServerSideProvider;
@ -155,7 +148,7 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::GetPatternProvider(_In_ PATTERNID patt
if (patternId == UIA_TextPatternId)
{
hr = this->QueryInterface(__uuidof(ITextProvider), reinterpret_cast<void**>(ppInterface));
hr = this->QueryInterface(IID_PPV_ARGS(ppInterface));
if (FAILED(hr))
{
*ppInterface = nullptr;
@ -167,7 +160,7 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::GetPatternProvider(_In_ PATTERNID patt
// Implementation of IRawElementProviderSimple::get_PropertyValue.
// Gets custom properties.
IFACEMETHODIMP ScreenInfoUiaProviderBase::GetPropertyValue(_In_ PROPERTYID propertyId,
_Out_ VARIANT* pVariant)
_Out_ VARIANT* pVariant) noexcept
{
// TODO GitHub #1914: Re-attach Tracing to UIA Tree
//Tracing::s_TraceUia(this, ApiCall::GetPropertyValue, nullptr);
@ -237,7 +230,7 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::GetPropertyValue(_In_ PROPERTYID prope
return S_OK;
}
IFACEMETHODIMP ScreenInfoUiaProviderBase::get_HostRawElementProvider(_COM_Outptr_result_maybenull_ IRawElementProviderSimple** ppProvider)
IFACEMETHODIMP ScreenInfoUiaProviderBase::get_HostRawElementProvider(_COM_Outptr_result_maybenull_ IRawElementProviderSimple** ppProvider) noexcept
{
// TODO GitHub #1914: Re-attach Tracing to UIA Tree
//Tracing::s_TraceUia(this, ApiCall::GetHostRawElementProvider, nullptr);
@ -260,15 +253,17 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::GetRuntimeId(_Outptr_result_maybenull_
*ppRuntimeId = nullptr;
// AppendRuntimeId is a magic Number that tells UIAutomation to Append its own Runtime ID(From the HWND)
int rId[] = { UiaAppendRuntimeId, -1 };
const std::array<int, 2> rId{ UiaAppendRuntimeId, -1 };
const std::basic_string_view<int> span{ rId.data(), rId.size() };
// BuildIntSafeArray is a custom function to hide the SafeArray creation
*ppRuntimeId = BuildIntSafeArray(rId, 2);
*ppRuntimeId = BuildIntSafeArray(span);
RETURN_IF_NULL_ALLOC(*ppRuntimeId);
return S_OK;
}
IFACEMETHODIMP ScreenInfoUiaProviderBase::GetEmbeddedFragmentRoots(_Outptr_result_maybenull_ SAFEARRAY** ppRoots)
IFACEMETHODIMP ScreenInfoUiaProviderBase::GetEmbeddedFragmentRoots(_Outptr_result_maybenull_ SAFEARRAY** ppRoots) noexcept
{
// TODO GitHub #1914: Re-attach Tracing to UIA Tree
//Tracing::s_TraceUia(this, ApiCall::GetEmbeddedFragmentRoots, nullptr);
@ -296,11 +291,11 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::GetSelection(_Outptr_result_maybenull_
//ApiMsgGetSelection apiMsg;
_LockConsole();
auto Unlock = wil::scope_exit([&] {
auto Unlock = wil::scope_exit([&]() noexcept {
_UnlockConsole();
});
RETURN_HR_IF(E_INVALIDARG, ppRetVal == nullptr);
RETURN_HR_IF_NULL(E_INVALIDARG, ppRetVal);
*ppRetVal = nullptr;
HRESULT hr = S_OK;
@ -322,6 +317,11 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::GetSelection(_Outptr_result_maybenull_
IRawElementProviderSimple* pProvider;
hr = this->QueryInterface(IID_PPV_ARGS(&pProvider));
if (pProvider == nullptr)
{
hr = E_POINTER;
}
if (FAILED(hr))
{
SafeArrayDestroy(*ppRetVal);
@ -340,7 +340,7 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::GetSelection(_Outptr_result_maybenull_
range = nullptr;
hr = wil::ResultFromCaughtException();
}
(static_cast<IUnknown*>(pProvider))->Release();
pProvider->Release();
if (range == nullptr)
{
SafeArrayDestroy(*ppRetVal);
@ -349,7 +349,7 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::GetSelection(_Outptr_result_maybenull_
}
LONG currentIndex = 0;
hr = SafeArrayPutElement(*ppRetVal, &currentIndex, reinterpret_cast<void*>(range));
hr = SafeArrayPutElement(*ppRetVal, &currentIndex, range);
if (FAILED(hr))
{
SafeArrayDestroy(*ppRetVal);
@ -363,6 +363,7 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::GetSelection(_Outptr_result_maybenull_
std::deque<UiaTextRangeBase*> ranges;
IRawElementProviderSimple* pProvider;
RETURN_IF_FAILED(QueryInterface(IID_PPV_ARGS(&pProvider)));
RETURN_HR_IF_NULL(E_POINTER, pProvider);
try
{
ranges = GetSelectionRanges(pProvider);
@ -379,25 +380,28 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::GetSelection(_Outptr_result_maybenull_
//apiMsg.SelectionRowCount = static_cast<unsigned int>(ranges.size());
// make a safe array
*ppRetVal = SafeArrayCreateVector(VT_UNKNOWN, 0, static_cast<ULONG>(ranges.size()));
*ppRetVal = SafeArrayCreateVector(VT_UNKNOWN, 0, gsl::narrow<ULONG>(ranges.size()));
if (*ppRetVal == nullptr)
{
return E_OUTOFMEMORY;
}
// fill the safe array
for (LONG i = 0; i < static_cast<LONG>(ranges.size()); ++i)
for (LONG i = 0; i < gsl::narrow<LONG>(ranges.size()); ++i)
{
hr = SafeArrayPutElement(*ppRetVal, &i, reinterpret_cast<void*>(ranges[i]));
hr = SafeArrayPutElement(*ppRetVal, &i, ranges.at(i));
if (FAILED(hr))
{
SafeArrayDestroy(*ppRetVal);
*ppRetVal = nullptr;
while (!ranges.empty())
{
UiaTextRangeBase* pRange = ranges[0];
UiaTextRangeBase* pRange = ranges.at(0);
ranges.pop_front();
pRange->Release();
if (pRange)
{
pRange->Release();
}
}
return hr;
}
@ -415,11 +419,11 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::GetVisibleRanges(_Outptr_result_mayben
//Tracing::s_TraceUia(this, ApiCall::GetVisibleRanges, nullptr);
_LockConsole();
auto Unlock = wil::scope_exit([&] {
auto Unlock = wil::scope_exit([&]() noexcept {
_UnlockConsole();
});
RETURN_HR_IF(E_INVALIDARG, ppRetVal == nullptr);
RETURN_HR_IF_NULL(E_INVALIDARG, ppRetVal);
*ppRetVal = nullptr;
const auto viewport = _getViewport();
@ -428,7 +432,7 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::GetVisibleRanges(_Outptr_result_mayben
// make a safe array
const size_t rowCount = viewport.Height();
*ppRetVal = SafeArrayCreateVector(VT_UNKNOWN, 0, static_cast<ULONG>(rowCount));
*ppRetVal = SafeArrayCreateVector(VT_UNKNOWN, 0, gsl::narrow<ULONG>(rowCount));
if (*ppRetVal == nullptr)
{
return E_OUTOFMEMORY;
@ -444,6 +448,11 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::GetVisibleRanges(_Outptr_result_mayben
IRawElementProviderSimple* pProvider;
HRESULT hr = this->QueryInterface(IID_PPV_ARGS(&pProvider));
if (pProvider == nullptr)
{
hr = E_POINTER;
}
if (FAILED(hr))
{
SafeArrayDestroy(*ppRetVal);
@ -464,7 +473,7 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::GetVisibleRanges(_Outptr_result_mayben
range = nullptr;
hr = wil::ResultFromCaughtException();
}
(static_cast<IUnknown*>(pProvider))->Release();
pProvider->Release();
if (range == nullptr)
{
@ -473,8 +482,8 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::GetVisibleRanges(_Outptr_result_mayben
return hr;
}
LONG currentIndex = static_cast<LONG>(i);
hr = SafeArrayPutElement(*ppRetVal, &currentIndex, reinterpret_cast<void*>(range));
LONG currentIndex = gsl::narrow<LONG>(i);
hr = SafeArrayPutElement(*ppRetVal, &currentIndex, range);
if (FAILED(hr))
{
SafeArrayDestroy(*ppRetVal);
@ -491,11 +500,12 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::RangeFromChild(_In_ IRawElementProvide
// TODO GitHub #1914: Re-attach Tracing to UIA Tree
//Tracing::s_TraceUia(this, ApiCall::RangeFromChild, nullptr);
RETURN_HR_IF(E_INVALIDARG, ppRetVal == nullptr);
RETURN_HR_IF_NULL(E_INVALIDARG, ppRetVal);
*ppRetVal = nullptr;
IRawElementProviderSimple* pProvider;
RETURN_IF_FAILED(this->QueryInterface(IID_PPV_ARGS(&pProvider)));
RETURN_HR_IF_NULL(E_POINTER, pProvider);
HRESULT hr = S_OK;
try
@ -507,7 +517,7 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::RangeFromChild(_In_ IRawElementProvide
*ppRetVal = nullptr;
hr = wil::ResultFromCaughtException();
}
(static_cast<IUnknown*>(pProvider))->Release();
pProvider->Release();
return hr;
}
@ -518,11 +528,12 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::RangeFromPoint(_In_ UiaPoint point,
// TODO GitHub #1914: Re-attach Tracing to UIA Tree
//Tracing::s_TraceUia(this, ApiCall::RangeFromPoint, nullptr);
RETURN_HR_IF(E_INVALIDARG, ppRetVal == nullptr);
RETURN_HR_IF_NULL(E_INVALIDARG, ppRetVal);
*ppRetVal = nullptr;
IRawElementProviderSimple* pProvider;
RETURN_IF_FAILED(this->QueryInterface(IID_PPV_ARGS(&pProvider)));
RETURN_HR_IF_NULL(E_POINTER, pProvider);
HRESULT hr = S_OK;
try
@ -535,7 +546,7 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::RangeFromPoint(_In_ UiaPoint point,
*ppRetVal = nullptr;
hr = wil::ResultFromCaughtException();
}
(static_cast<IUnknown*>(pProvider))->Release();
pProvider->Release();
return hr;
}
@ -545,11 +556,12 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::get_DocumentRange(_COM_Outptr_result_m
// TODO GitHub #1914: Re-attach Tracing to UIA Tree
//Tracing::s_TraceUia(this, ApiCall::GetDocumentRange, nullptr);
RETURN_HR_IF(E_INVALIDARG, ppRetVal == nullptr);
RETURN_HR_IF_NULL(E_INVALIDARG, ppRetVal);
*ppRetVal = nullptr;
IRawElementProviderSimple* pProvider;
RETURN_IF_FAILED(this->QueryInterface(IID_PPV_ARGS(&pProvider)));
RETURN_HR_IF_NULL(E_POINTER, pProvider);
HRESULT hr = S_OK;
try
@ -561,7 +573,7 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::get_DocumentRange(_COM_Outptr_result_m
*ppRetVal = nullptr;
hr = wil::ResultFromCaughtException();
}
(static_cast<IUnknown*>(pProvider))->Release();
pProvider->Release();
if (*ppRetVal)
{
@ -571,8 +583,10 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::get_DocumentRange(_COM_Outptr_result_m
return hr;
}
IFACEMETHODIMP ScreenInfoUiaProviderBase::get_SupportedTextSelection(_Out_ SupportedTextSelection* pRetVal)
IFACEMETHODIMP ScreenInfoUiaProviderBase::get_SupportedTextSelection(_Out_ SupportedTextSelection* pRetVal) noexcept
{
RETURN_HR_IF_NULL(E_INVALIDARG, pRetVal);
// TODO GitHub #1914: Re-attach Tracing to UIA Tree
//Tracing::s_TraceUia(this, ApiCall::GetSupportedTextSelection, nullptr);
@ -587,12 +601,12 @@ const COORD ScreenInfoUiaProviderBase::_getScreenBufferCoords() const
return _getTextBuffer().GetSize().Dimensions();
}
const TextBuffer& ScreenInfoUiaProviderBase::_getTextBuffer() const
const TextBuffer& ScreenInfoUiaProviderBase::_getTextBuffer() const noexcept
{
return _pData->GetTextBuffer();
}
const Viewport ScreenInfoUiaProviderBase::_getViewport() const
const Viewport ScreenInfoUiaProviderBase::_getViewport() const noexcept
{
return _pData->GetViewport();
}

View file

@ -38,44 +38,48 @@ namespace Microsoft::Console::Types
{
public:
ScreenInfoUiaProviderBase(_In_ IUiaData* pData);
virtual ~ScreenInfoUiaProviderBase();
ScreenInfoUiaProviderBase(const ScreenInfoUiaProviderBase&) = default;
ScreenInfoUiaProviderBase(ScreenInfoUiaProviderBase&&) = default;
ScreenInfoUiaProviderBase& operator=(const ScreenInfoUiaProviderBase&) = default;
ScreenInfoUiaProviderBase& operator=(ScreenInfoUiaProviderBase&&) = default;
virtual ~ScreenInfoUiaProviderBase() = default;
[[nodiscard]] HRESULT Signal(_In_ EVENTID id);
// IUnknown methods
IFACEMETHODIMP_(ULONG)
AddRef();
AddRef() override;
IFACEMETHODIMP_(ULONG)
Release();
Release() override;
IFACEMETHODIMP QueryInterface(_In_ REFIID riid,
_COM_Outptr_result_maybenull_ void** ppInterface);
_COM_Outptr_result_maybenull_ void** ppInterface) override;
// IRawElementProviderSimple methods
IFACEMETHODIMP get_ProviderOptions(_Out_ ProviderOptions* pOptions);
IFACEMETHODIMP get_ProviderOptions(_Out_ ProviderOptions* pOptions) noexcept override;
IFACEMETHODIMP GetPatternProvider(_In_ PATTERNID iid,
_COM_Outptr_result_maybenull_ IUnknown** ppInterface);
_COM_Outptr_result_maybenull_ IUnknown** ppInterface) override;
IFACEMETHODIMP GetPropertyValue(_In_ PROPERTYID idProp,
_Out_ VARIANT* pVariant);
IFACEMETHODIMP get_HostRawElementProvider(_COM_Outptr_result_maybenull_ IRawElementProviderSimple** ppProvider);
_Out_ VARIANT* pVariant) noexcept override;
IFACEMETHODIMP get_HostRawElementProvider(_COM_Outptr_result_maybenull_ IRawElementProviderSimple** ppProvider) noexcept override;
// IRawElementProviderFragment methods
virtual IFACEMETHODIMP Navigate(_In_ NavigateDirection direction,
_COM_Outptr_result_maybenull_ IRawElementProviderFragment** ppProvider) = 0;
IFACEMETHODIMP GetRuntimeId(_Outptr_result_maybenull_ SAFEARRAY** ppRuntimeId);
IFACEMETHODIMP GetRuntimeId(_Outptr_result_maybenull_ SAFEARRAY** ppRuntimeId) override;
virtual IFACEMETHODIMP get_BoundingRectangle(_Out_ UiaRect* pRect) = 0;
IFACEMETHODIMP GetEmbeddedFragmentRoots(_Outptr_result_maybenull_ SAFEARRAY** ppRoots);
IFACEMETHODIMP SetFocus();
IFACEMETHODIMP GetEmbeddedFragmentRoots(_Outptr_result_maybenull_ SAFEARRAY** ppRoots) noexcept override;
IFACEMETHODIMP SetFocus() override;
virtual IFACEMETHODIMP get_FragmentRoot(_COM_Outptr_result_maybenull_ IRawElementProviderFragmentRoot** ppProvider) = 0;
// ITextProvider
IFACEMETHODIMP GetSelection(_Outptr_result_maybenull_ SAFEARRAY** ppRetVal);
IFACEMETHODIMP GetVisibleRanges(_Outptr_result_maybenull_ SAFEARRAY** ppRetVal);
IFACEMETHODIMP GetSelection(_Outptr_result_maybenull_ SAFEARRAY** ppRetVal) override;
IFACEMETHODIMP GetVisibleRanges(_Outptr_result_maybenull_ SAFEARRAY** ppRetVal) override;
IFACEMETHODIMP RangeFromChild(_In_ IRawElementProviderSimple* childElement,
_COM_Outptr_result_maybenull_ ITextRangeProvider** ppRetVal);
_COM_Outptr_result_maybenull_ ITextRangeProvider** ppRetVal) override;
IFACEMETHODIMP RangeFromPoint(_In_ UiaPoint point,
_COM_Outptr_result_maybenull_ ITextRangeProvider** ppRetVal);
IFACEMETHODIMP get_DocumentRange(_COM_Outptr_result_maybenull_ ITextRangeProvider** ppRetVal);
IFACEMETHODIMP get_SupportedTextSelection(_Out_ SupportedTextSelection* pRetVal);
_COM_Outptr_result_maybenull_ ITextRangeProvider** ppRetVal) override;
IFACEMETHODIMP get_DocumentRange(_COM_Outptr_result_maybenull_ ITextRangeProvider** ppRetVal) override;
IFACEMETHODIMP get_SupportedTextSelection(_Out_ SupportedTextSelection* pRetVal) noexcept override;
protected:
virtual std::deque<UiaTextRangeBase*> GetSelectionRanges(_In_ IRawElementProviderSimple* pProvider) = 0;
@ -118,8 +122,8 @@ namespace Microsoft::Console::Types
std::map<EVENTID, bool> _signalFiringMapping;
const COORD _getScreenBufferCoords() const;
const TextBuffer& _getTextBuffer() const;
const Viewport _getViewport() const;
const TextBuffer& _getTextBuffer() const noexcept;
const Viewport _getViewport() const noexcept;
void _LockConsole() noexcept;
void _UnlockConsole() noexcept;
};

View file

@ -6,8 +6,10 @@
#include <type_traits>
#include <utility>
UTF8OutPipeReader::UTF8OutPipeReader(HANDLE outPipe) :
_outPipe{ outPipe }
UTF8OutPipeReader::UTF8OutPipeReader(HANDLE outPipe) noexcept :
_outPipe{ outPipe },
_buffer{ 0 },
_utf8Partials{ 0 }
{
}
@ -30,24 +32,24 @@ UTF8OutPipeReader::UTF8OutPipeReader(HANDLE outPipe) :
bool fSuccess{};
// in case of early escaping
*_buffer = 0;
strView = std::string_view{ reinterpret_cast<char*>(_buffer), 0 };
_buffer.at(0) = 0;
strView = std::string_view{ _buffer.data(), 0 };
// copy UTF-8 code units that were remaining from the previously read chunk (if any)
if (_dwPartialsLen != 0)
{
std::move(_utf8Partials, _utf8Partials + _dwPartialsLen, _buffer);
std::move(_utf8Partials.cbegin(), _utf8Partials.cbegin() + _dwPartialsLen, _buffer.begin());
}
// try to read data
fSuccess = !!ReadFile(_outPipe, &_buffer[_dwPartialsLen], std::extent<decltype(_buffer)>::value - _dwPartialsLen, &dwRead, nullptr);
fSuccess = !!ReadFile(_outPipe, &_buffer.at(_dwPartialsLen), gsl::narrow<DWORD>(_buffer.size()) - _dwPartialsLen, &dwRead, nullptr);
dwRead += _dwPartialsLen;
_dwPartialsLen = 0;
if (!fSuccess) // reading failed (we must check this first, because dwRead will also be 0.)
{
auto lastError = GetLastError();
const auto lastError = GetLastError();
if (lastError == ERROR_BROKEN_PIPE)
{
// This is a successful, but detectable, exit.
@ -65,13 +67,13 @@ UTF8OutPipeReader::UTF8OutPipeReader(HANDLE outPipe) :
return S_OK;
}
const BYTE* const endPtr{ _buffer + dwRead };
const BYTE* backIter{ endPtr - 1 };
const auto endPtr = _buffer.cbegin() + dwRead;
auto backIter = endPtr - 1;
// If the last byte in the buffer was a byte belonging to a UTF-8 multi-byte character
if ((*backIter & _Utf8BitMasks::MaskAsciiByte) > _Utf8BitMasks::IsAsciiByte)
{
// Check only up to 3 last bytes, if no Lead Byte was found then the byte before must be the Lead Byte and no partials are in the buffer
for (DWORD dwSequenceLen{ 1UL }, stop{ dwRead < 4UL ? dwRead : 4UL }; dwSequenceLen < stop; ++dwSequenceLen, --backIter)
for (DWORD dwSequenceLen{ 1UL }; dwSequenceLen < std::min(dwRead, 4UL); ++dwSequenceLen, --backIter)
{
// If Lead Byte found
if ((*backIter & _Utf8BitMasks::MaskContinuationByte) > _Utf8BitMasks::IsContinuationByte)
@ -80,9 +82,9 @@ UTF8OutPipeReader::UTF8OutPipeReader(HANDLE outPipe) :
// Use the bitmask at index `dwSequenceLen`. Compare the result with the operand having the same index. If they
// are not equal then the sequence has to be cached because it is a partial code point. Otherwise the
// sequence is a complete UTF-8 code point and the whole buffer is ready for the conversion to hstring.
if ((*backIter & _cmpMasks[dwSequenceLen]) != _cmpOperands[dwSequenceLen])
if ((*backIter & _cmpMasks.at(dwSequenceLen)) != _cmpOperands.at(dwSequenceLen))
{
std::move(backIter, endPtr, _utf8Partials);
std::move(backIter, endPtr, _utf8Partials.begin());
dwRead -= dwSequenceLen;
_dwPartialsLen = dwSequenceLen;
}
@ -93,6 +95,6 @@ UTF8OutPipeReader::UTF8OutPipeReader(HANDLE outPipe) :
}
// give back a view of the part of the buffer that contains complete code points only
strView = std::string_view{ reinterpret_cast<char*>(_buffer), dwRead };
strView = std::string_view{ &_buffer.at(0), dwRead };
return S_OK;
}

File diff suppressed because it is too large Load diff

View file

@ -129,7 +129,7 @@ namespace Microsoft::Console::Types
const Column firstColumnInRow,
const Column lastColumnInRow,
const MovementIncrement increment,
const MovementDirection direction);
const MovementDirection direction) noexcept;
#ifdef UNIT_TESTING
friend class ::UiaTextRangeTests;
@ -137,62 +137,65 @@ namespace Microsoft::Console::Types
};
public:
UiaTextRangeBase(UiaTextRangeBase&&) = default;
UiaTextRangeBase& operator=(const UiaTextRangeBase&) = default;
UiaTextRangeBase& operator=(UiaTextRangeBase&&) = default;
virtual ~UiaTextRangeBase() = default;
const IdType GetId() const;
const Endpoint GetStart() const;
const Endpoint GetEnd() const;
const bool IsDegenerate() const;
const IdType GetId() const noexcept;
const Endpoint GetStart() const noexcept;
const Endpoint GetEnd() const noexcept;
const bool IsDegenerate() const noexcept;
// TODO GitHub #605:
// only used for UiaData::FindText. Remove after Search added properly
void SetRangeValues(const Endpoint start, const Endpoint end, const bool isDegenerate);
void SetRangeValues(const Endpoint start, const Endpoint end, const bool isDegenerate) noexcept;
// IUnknown methods
IFACEMETHODIMP_(ULONG)
AddRef();
AddRef() override;
IFACEMETHODIMP_(ULONG)
Release();
Release() override;
IFACEMETHODIMP QueryInterface(_In_ REFIID riid,
_COM_Outptr_result_maybenull_ void** ppInterface);
_COM_Outptr_result_maybenull_ void** ppInterface) override;
// ITextRangeProvider methods
virtual IFACEMETHODIMP Clone(_Outptr_result_maybenull_ ITextRangeProvider** ppRetVal) = 0;
IFACEMETHODIMP Compare(_In_opt_ ITextRangeProvider* pRange, _Out_ BOOL* pRetVal);
IFACEMETHODIMP Compare(_In_opt_ ITextRangeProvider* pRange, _Out_ BOOL* pRetVal) noexcept override;
IFACEMETHODIMP CompareEndpoints(_In_ TextPatternRangeEndpoint endpoint,
_In_ ITextRangeProvider* pTargetRange,
_In_ TextPatternRangeEndpoint targetEndpoint,
_Out_ int* pRetVal);
IFACEMETHODIMP ExpandToEnclosingUnit(_In_ TextUnit unit);
_Out_ int* pRetVal) noexcept override;
IFACEMETHODIMP ExpandToEnclosingUnit(_In_ TextUnit unit) override;
IFACEMETHODIMP FindAttribute(_In_ TEXTATTRIBUTEID textAttributeId,
_In_ VARIANT val,
_In_ BOOL searchBackward,
_Outptr_result_maybenull_ ITextRangeProvider** ppRetVal);
_Outptr_result_maybenull_ ITextRangeProvider** ppRetVal) noexcept override;
virtual IFACEMETHODIMP FindText(_In_ BSTR text,
_In_ BOOL searchBackward,
_In_ BOOL ignoreCase,
_Outptr_result_maybenull_ ITextRangeProvider** ppRetVal) = 0;
IFACEMETHODIMP GetAttributeValue(_In_ TEXTATTRIBUTEID textAttributeId,
_Out_ VARIANT* pRetVal);
IFACEMETHODIMP GetBoundingRectangles(_Outptr_result_maybenull_ SAFEARRAY** ppRetVal);
IFACEMETHODIMP GetEnclosingElement(_Outptr_result_maybenull_ IRawElementProviderSimple** ppRetVal);
_Out_ VARIANT* pRetVal) noexcept override;
IFACEMETHODIMP GetBoundingRectangles(_Outptr_result_maybenull_ SAFEARRAY** ppRetVal) override;
IFACEMETHODIMP GetEnclosingElement(_Outptr_result_maybenull_ IRawElementProviderSimple** ppRetVal) override;
IFACEMETHODIMP GetText(_In_ int maxLength,
_Out_ BSTR* pRetVal);
_Out_ BSTR* pRetVal) override;
IFACEMETHODIMP Move(_In_ TextUnit unit,
_In_ int count,
_Out_ int* pRetVal);
_Out_ int* pRetVal) override;
IFACEMETHODIMP MoveEndpointByUnit(_In_ TextPatternRangeEndpoint endpoint,
_In_ TextUnit unit,
_In_ int count,
_Out_ int* pRetVal);
_Out_ int* pRetVal) override;
IFACEMETHODIMP MoveEndpointByRange(_In_ TextPatternRangeEndpoint endpoint,
_In_ ITextRangeProvider* pTargetRange,
_In_ TextPatternRangeEndpoint targetEndpoint);
IFACEMETHODIMP Select();
IFACEMETHODIMP AddToSelection();
IFACEMETHODIMP RemoveFromSelection();
IFACEMETHODIMP ScrollIntoView(_In_ BOOL alignToTop);
IFACEMETHODIMP GetChildren(_Outptr_result_maybenull_ SAFEARRAY** ppRetVal);
_In_ TextPatternRangeEndpoint targetEndpoint) override;
IFACEMETHODIMP Select() override;
IFACEMETHODIMP AddToSelection() noexcept override;
IFACEMETHODIMP RemoveFromSelection() noexcept override;
IFACEMETHODIMP ScrollIntoView(_In_ BOOL alignToTop) override;
IFACEMETHODIMP GetChildren(_Outptr_result_maybenull_ SAFEARRAY** ppRetVal) noexcept override;
protected:
#if _DEBUG
@ -225,7 +228,7 @@ namespace Microsoft::Console::Types
void Initialize(_In_ const UiaPoint point);
UiaTextRangeBase(const UiaTextRangeBase& a);
UiaTextRangeBase(const UiaTextRangeBase& a) noexcept;
// used to debug objects passed back and forth
// between the provider and the client
@ -259,126 +262,136 @@ namespace Microsoft::Console::Types
RECT _getTerminalRect() const;
static const COORD _getScreenBufferCoords(IUiaData* pData);
static const COORD _getScreenBufferCoords(gsl::not_null<IUiaData*> pData);
virtual const COORD _getScreenFontSize() const;
static const unsigned int _getTotalRows(IUiaData* pData);
static const unsigned int _getRowWidth(IUiaData* pData);
static const unsigned int _getTotalRows(gsl::not_null<IUiaData*> pData) noexcept;
static const unsigned int _getRowWidth(gsl::not_null<IUiaData*> pData);
static const unsigned int _getFirstScreenInfoRowIndex();
static const unsigned int _getLastScreenInfoRowIndex(IUiaData* pData);
static const unsigned int _getFirstScreenInfoRowIndex() noexcept;
static const unsigned int _getLastScreenInfoRowIndex(gsl::not_null<IUiaData*> pData) noexcept;
static const Column _getFirstColumnIndex();
static const Column _getLastColumnIndex(IUiaData* pData);
static const Column _getFirstColumnIndex() noexcept;
static const Column _getLastColumnIndex(gsl::not_null<IUiaData*> pData);
const unsigned int _rowCountInRange(IUiaData* pData) const;
const unsigned int _rowCountInRange(gsl::not_null<IUiaData*> pData) const;
static const TextBufferRow _endpointToTextBufferRow(IUiaData* pData,
static const TextBufferRow _endpointToTextBufferRow(gsl::not_null<IUiaData*> pData,
const Endpoint endpoint);
static const ScreenInfoRow _textBufferRowToScreenInfoRow(IUiaData* pData,
const TextBufferRow row);
static const ScreenInfoRow _textBufferRowToScreenInfoRow(gsl::not_null<IUiaData*> pData,
const TextBufferRow row) noexcept;
static const TextBufferRow _screenInfoRowToTextBufferRow(IUiaData* pData,
const ScreenInfoRow row);
static const Endpoint _textBufferRowToEndpoint(IUiaData* pData, const TextBufferRow row);
static const TextBufferRow _screenInfoRowToTextBufferRow(gsl::not_null<IUiaData*> pData,
const ScreenInfoRow row) noexcept;
static const Endpoint _textBufferRowToEndpoint(gsl::not_null<IUiaData*> pData, const TextBufferRow row);
static const ScreenInfoRow _endpointToScreenInfoRow(IUiaData* pData,
static const ScreenInfoRow _endpointToScreenInfoRow(gsl::not_null<IUiaData*> pData,
const Endpoint endpoint);
static const Endpoint _screenInfoRowToEndpoint(IUiaData* pData,
static const Endpoint _screenInfoRowToEndpoint(gsl::not_null<IUiaData*> pData,
const ScreenInfoRow row);
static COORD _endpointToCoord(IUiaData* pData,
static COORD _endpointToCoord(gsl::not_null<IUiaData*> pData,
const Endpoint endpoint);
static Endpoint _coordToEndpoint(IUiaData* pData,
static Endpoint _coordToEndpoint(gsl::not_null<IUiaData*> pData,
const COORD coord);
static const Column _endpointToColumn(IUiaData* pData,
static const Column _endpointToColumn(gsl::not_null<IUiaData*> pData,
const Endpoint endpoint);
static const Row _normalizeRow(IUiaData* pData, const Row row);
static const Row _normalizeRow(gsl::not_null<IUiaData*> pData, const Row row) noexcept;
static const ViewportRow _screenInfoRowToViewportRow(IUiaData* pData,
const ScreenInfoRow row);
static const ViewportRow _screenInfoRowToViewportRow(const ScreenInfoRow row,
const SMALL_RECT viewport);
static const ViewportRow _screenInfoRowToViewportRow(gsl::not_null<IUiaData*> pData,
const ScreenInfoRow row) noexcept;
// Routine Description:
// - Converts a ScreenInfoRow to a ViewportRow.
// Arguments:
// - row - the ScreenInfoRow to convert
// - viewport - the viewport to use for the conversion
// Return Value:
// - the equivalent ViewportRow.
static constexpr const ViewportRow _screenInfoRowToViewportRow(const ScreenInfoRow row,
const SMALL_RECT viewport) noexcept
{
return row - viewport.Top;
}
static const bool _isScreenInfoRowInViewport(IUiaData* pData,
const ScreenInfoRow row);
static const bool _isScreenInfoRowInViewport(gsl::not_null<IUiaData*> pData,
const ScreenInfoRow row) noexcept;
static const bool _isScreenInfoRowInViewport(const ScreenInfoRow row,
const SMALL_RECT viewport);
const SMALL_RECT viewport) noexcept;
static const unsigned int _getViewportHeight(const SMALL_RECT viewport);
static const unsigned int _getViewportWidth(const SMALL_RECT viewport);
static const unsigned int _getViewportHeight(const SMALL_RECT viewport) noexcept;
static const unsigned int _getViewportWidth(const SMALL_RECT viewport) noexcept;
void _addScreenInfoRowBoundaries(IUiaData* pData,
void _addScreenInfoRowBoundaries(gsl::not_null<IUiaData*> pData,
const ScreenInfoRow screenInfoRow,
_Inout_ std::vector<double>& coords) const;
static const int _compareScreenCoords(IUiaData* pData,
static const int _compareScreenCoords(gsl::not_null<IUiaData*> pData,
const ScreenInfoRow rowA,
const Column colA,
const ScreenInfoRow rowB,
const Column colB);
static std::pair<Endpoint, Endpoint> _moveByCharacter(IUiaData* pData,
static std::pair<Endpoint, Endpoint> _moveByCharacter(gsl::not_null<IUiaData*> pData,
const int moveCount,
const MoveState moveState,
_Out_ int* const pAmountMoved);
_Out_ gsl::not_null<int*> const pAmountMoved);
static std::pair<Endpoint, Endpoint> _moveByCharacterForward(IUiaData* pData,
static std::pair<Endpoint, Endpoint> _moveByCharacterForward(gsl::not_null<IUiaData*> pData,
const int moveCount,
const MoveState moveState,
_Out_ int* const pAmountMoved);
_Out_ gsl::not_null<int*> const pAmountMoved);
static std::pair<Endpoint, Endpoint> _moveByCharacterBackward(IUiaData* pData,
static std::pair<Endpoint, Endpoint> _moveByCharacterBackward(gsl::not_null<IUiaData*> pData,
const int moveCount,
const MoveState moveState,
_Out_ int* const pAmountMoved);
_Out_ gsl::not_null<int*> const pAmountMoved);
static std::pair<Endpoint, Endpoint> _moveByLine(IUiaData* pData,
static std::pair<Endpoint, Endpoint> _moveByLine(gsl::not_null<IUiaData*> pData,
const int moveCount,
const MoveState moveState,
_Out_ int* const pAmountMoved);
_Out_ gsl::not_null<int*> const pAmountMoved);
static std::pair<Endpoint, Endpoint> _moveByDocument(IUiaData* pData,
static std::pair<Endpoint, Endpoint> _moveByDocument(gsl::not_null<IUiaData*> pData,
const int moveCount,
const MoveState moveState,
_Out_ int* const pAmountMoved);
_Out_ gsl::not_null<int*> const pAmountMoved);
static std::tuple<Endpoint, Endpoint, bool>
_moveEndpointByUnitCharacter(IUiaData* pData,
_moveEndpointByUnitCharacter(gsl::not_null<IUiaData*> pData,
const int moveCount,
const TextPatternRangeEndpoint endpoint,
const MoveState moveState,
_Out_ int* const pAmountMoved);
_Out_ gsl::not_null<int*> const pAmountMoved);
static std::tuple<Endpoint, Endpoint, bool>
_moveEndpointByUnitCharacterForward(IUiaData* pData,
_moveEndpointByUnitCharacterForward(gsl::not_null<IUiaData*> pData,
const int moveCount,
const TextPatternRangeEndpoint endpoint,
const MoveState moveState,
_Out_ int* const pAmountMoved);
_Out_ gsl::not_null<int*> const pAmountMoved);
static std::tuple<Endpoint, Endpoint, bool>
_moveEndpointByUnitCharacterBackward(IUiaData* pData,
_moveEndpointByUnitCharacterBackward(gsl::not_null<IUiaData*> pData,
const int moveCount,
const TextPatternRangeEndpoint endpoint,
const MoveState moveState,
_Out_ int* const pAmountMoved);
_Out_ gsl::not_null<int*> const pAmountMoved);
static std::tuple<Endpoint, Endpoint, bool>
_moveEndpointByUnitLine(IUiaData* pData,
_moveEndpointByUnitLine(gsl::not_null<IUiaData*> pData,
const int moveCount,
const TextPatternRangeEndpoint endpoint,
const MoveState moveState,
_Out_ int* const pAmountMoved);
_Out_ gsl::not_null<int*> const pAmountMoved);
static std::tuple<Endpoint, Endpoint, bool>
_moveEndpointByUnitDocument(IUiaData* pData,
_moveEndpointByUnitDocument(gsl::not_null<IUiaData*> pData,
const int moveCount,
const TextPatternRangeEndpoint endpoint,
const MoveState moveState,
_Out_ int* const pAmountMoved);
_Out_ gsl::not_null<int*> const pAmountMoved);
#ifdef UNIT_TESTING
friend class ::UiaTextRangeTests;

View file

@ -14,7 +14,7 @@
// - wstr - The UTF-16 string to parse.
// Return Value:
// - A view into the string given of just the next codepoint unit.
std::wstring_view Utf16Parser::ParseNext(std::wstring_view wstr)
std::wstring_view Utf16Parser::ParseNext(std::wstring_view wstr) noexcept
{
for (size_t pos = 0; pos < wstr.size(); ++pos)
{

View file

@ -26,7 +26,7 @@ WindowUiaProviderBase::AddRef()
IFACEMETHODIMP_(ULONG)
WindowUiaProviderBase::Release()
{
long val = InterlockedDecrement(&_cRefs);
const long val = InterlockedDecrement(&_cRefs);
if (val == 0)
{
delete this;
@ -36,21 +36,13 @@ WindowUiaProviderBase::Release()
IFACEMETHODIMP WindowUiaProviderBase::QueryInterface(_In_ REFIID riid, _COM_Outptr_result_maybenull_ void** ppInterface)
{
if (riid == __uuidof(IUnknown))
RETURN_HR_IF_NULL(E_INVALIDARG, ppInterface);
if (riid == __uuidof(IUnknown) ||
riid == __uuidof(IRawElementProviderSimple) ||
riid == __uuidof(IRawElementProviderFragment) ||
riid == __uuidof(IRawElementProviderFragmentRoot))
{
*ppInterface = static_cast<IRawElementProviderSimple*>(this);
}
else if (riid == __uuidof(IRawElementProviderSimple))
{
*ppInterface = static_cast<IRawElementProviderSimple*>(this);
}
else if (riid == __uuidof(IRawElementProviderFragment))
{
*ppInterface = static_cast<IRawElementProviderFragment*>(this);
}
else if (riid == __uuidof(IRawElementProviderFragmentRoot))
{
*ppInterface = static_cast<IRawElementProviderFragmentRoot*>(this);
*ppInterface = this;
}
else
{
@ -58,7 +50,7 @@ IFACEMETHODIMP WindowUiaProviderBase::QueryInterface(_In_ REFIID riid, _COM_Outp
return E_NOINTERFACE;
}
(static_cast<IUnknown*>(*ppInterface))->AddRef();
AddRef();
return S_OK;
}
@ -71,6 +63,7 @@ IFACEMETHODIMP WindowUiaProviderBase::QueryInterface(_In_ REFIID riid, _COM_Outp
// Gets UI Automation provider options.
IFACEMETHODIMP WindowUiaProviderBase::get_ProviderOptions(_Out_ ProviderOptions* pOptions)
{
RETURN_HR_IF_NULL(E_INVALIDARG, pOptions);
RETURN_IF_FAILED(_EnsureValidHwnd());
*pOptions = ProviderOptions_ServerSideProvider;
@ -82,6 +75,7 @@ IFACEMETHODIMP WindowUiaProviderBase::get_ProviderOptions(_Out_ ProviderOptions*
IFACEMETHODIMP WindowUiaProviderBase::GetPatternProvider(_In_ PATTERNID /*patternId*/,
_COM_Outptr_result_maybenull_ IUnknown** ppInterface)
{
RETURN_HR_IF_NULL(E_INVALIDARG, ppInterface);
*ppInterface = nullptr;
RETURN_IF_FAILED(_EnsureValidHwnd());
@ -92,6 +86,7 @@ IFACEMETHODIMP WindowUiaProviderBase::GetPatternProvider(_In_ PATTERNID /*patter
// Gets custom properties.
IFACEMETHODIMP WindowUiaProviderBase::GetPropertyValue(_In_ PROPERTYID propertyId, _Out_ VARIANT* pVariant)
{
RETURN_HR_IF_NULL(E_INVALIDARG, pVariant);
RETURN_IF_FAILED(_EnsureValidHwnd());
pVariant->vt = VT_EMPTY;
@ -148,6 +143,7 @@ IFACEMETHODIMP WindowUiaProviderBase::GetPropertyValue(_In_ PROPERTYID propertyI
// supplies many properties.
IFACEMETHODIMP WindowUiaProviderBase::get_HostRawElementProvider(_COM_Outptr_result_maybenull_ IRawElementProviderSimple** ppProvider)
{
RETURN_HR_IF_NULL(E_INVALIDARG, ppProvider);
try
{
const HWND hwnd = GetWindowHandle();
@ -155,7 +151,7 @@ IFACEMETHODIMP WindowUiaProviderBase::get_HostRawElementProvider(_COM_Outptr_res
}
catch (...)
{
return static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE);
return gsl::narrow_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE);
}
}
#pragma endregion
@ -164,6 +160,7 @@ IFACEMETHODIMP WindowUiaProviderBase::get_HostRawElementProvider(_COM_Outptr_res
IFACEMETHODIMP WindowUiaProviderBase::GetRuntimeId(_Outptr_result_maybenull_ SAFEARRAY** ppRuntimeId)
{
RETURN_HR_IF_NULL(E_INVALIDARG, ppRuntimeId);
RETURN_IF_FAILED(_EnsureValidHwnd());
// Root defers this to host, others must implement it...
*ppRuntimeId = nullptr;
@ -173,6 +170,7 @@ IFACEMETHODIMP WindowUiaProviderBase::GetRuntimeId(_Outptr_result_maybenull_ SAF
IFACEMETHODIMP WindowUiaProviderBase::get_BoundingRectangle(_Out_ UiaRect* pRect)
{
RETURN_HR_IF_NULL(E_INVALIDARG, pRect);
RETURN_IF_FAILED(_EnsureValidHwnd());
const IUiaWindow* const pConsoleWindow = _baseWindow;
@ -182,14 +180,20 @@ IFACEMETHODIMP WindowUiaProviderBase::get_BoundingRectangle(_Out_ UiaRect* pRect
pRect->left = rc.left;
pRect->top = rc.top;
pRect->width = rc.right - rc.left;
pRect->height = rc.bottom - rc.top;
LONG longWidth = 0;
RETURN_IF_FAILED(LongSub(rc.right, rc.left, &longWidth));
pRect->width = longWidth;
LONG longHeight = 0;
RETURN_IF_FAILED(LongSub(rc.bottom, rc.top, &longHeight));
pRect->height = longHeight;
return S_OK;
}
IFACEMETHODIMP WindowUiaProviderBase::GetEmbeddedFragmentRoots(_Outptr_result_maybenull_ SAFEARRAY** ppRoots)
{
RETURN_HR_IF_NULL(E_INVALIDARG, ppRoots);
RETURN_IF_FAILED(_EnsureValidHwnd());
*ppRoots = nullptr;
@ -198,6 +202,7 @@ IFACEMETHODIMP WindowUiaProviderBase::GetEmbeddedFragmentRoots(_Outptr_result_ma
IFACEMETHODIMP WindowUiaProviderBase::get_FragmentRoot(_COM_Outptr_result_maybenull_ IRawElementProviderFragmentRoot** ppProvider)
{
RETURN_HR_IF_NULL(E_INVALIDARG, ppProvider);
RETURN_IF_FAILED(_EnsureValidHwnd());
*ppProvider = this;
@ -209,10 +214,15 @@ IFACEMETHODIMP WindowUiaProviderBase::get_FragmentRoot(_COM_Outptr_result_mayben
HWND WindowUiaProviderBase::GetWindowHandle() const
{
IUiaWindow* const pConsoleWindow = _baseWindow;
THROW_HR_IF_NULL(E_POINTER, pConsoleWindow);
return pConsoleWindow->GetWindowHandle();
const IUiaWindow* const pConsoleWindow = _baseWindow;
if (pConsoleWindow)
{
return pConsoleWindow->GetWindowHandle();
}
else
{
return nullptr;
}
}
[[nodiscard]] HRESULT WindowUiaProviderBase::_EnsureValidHwnd() const

View file

@ -31,34 +31,44 @@ namespace Microsoft::Console::Types
public IRawElementProviderFragment,
public IRawElementProviderFragmentRoot
{
public:
virtual ~WindowUiaProviderBase() = default;
protected:
WindowUiaProviderBase() = default;
WindowUiaProviderBase(const WindowUiaProviderBase&) = default;
WindowUiaProviderBase(WindowUiaProviderBase&&) = default;
WindowUiaProviderBase& operator=(const WindowUiaProviderBase&) = default;
WindowUiaProviderBase& operator=(WindowUiaProviderBase&&) = default;
public:
[[nodiscard]] virtual HRESULT Signal(_In_ EVENTID id) = 0;
[[nodiscard]] virtual HRESULT SetTextAreaFocus() = 0;
// IUnknown methods
IFACEMETHODIMP_(ULONG)
AddRef();
AddRef() override;
IFACEMETHODIMP_(ULONG)
Release();
Release() override;
IFACEMETHODIMP QueryInterface(_In_ REFIID riid,
_COM_Outptr_result_maybenull_ void** ppInterface);
_COM_Outptr_result_maybenull_ void** ppInterface) override;
// IRawElementProviderSimple methods
IFACEMETHODIMP get_ProviderOptions(_Out_ ProviderOptions* pOptions);
IFACEMETHODIMP get_ProviderOptions(_Out_ ProviderOptions* pOptions) override;
IFACEMETHODIMP GetPatternProvider(_In_ PATTERNID iid,
_COM_Outptr_result_maybenull_ IUnknown** ppInterface);
_COM_Outptr_result_maybenull_ IUnknown** ppInterface) override;
IFACEMETHODIMP GetPropertyValue(_In_ PROPERTYID idProp,
_Out_ VARIANT* pVariant);
IFACEMETHODIMP get_HostRawElementProvider(_COM_Outptr_result_maybenull_ IRawElementProviderSimple** ppProvider);
_Out_ VARIANT* pVariant) override;
IFACEMETHODIMP get_HostRawElementProvider(_COM_Outptr_result_maybenull_ IRawElementProviderSimple** ppProvider) override;
// IRawElementProviderFragment methods
virtual IFACEMETHODIMP Navigate(_In_ NavigateDirection direction,
_COM_Outptr_result_maybenull_ IRawElementProviderFragment** ppProvider) = 0;
IFACEMETHODIMP GetRuntimeId(_Outptr_result_maybenull_ SAFEARRAY** ppRuntimeId);
IFACEMETHODIMP get_BoundingRectangle(_Out_ UiaRect* pRect);
IFACEMETHODIMP GetEmbeddedFragmentRoots(_Outptr_result_maybenull_ SAFEARRAY** ppRoots);
IFACEMETHODIMP GetRuntimeId(_Outptr_result_maybenull_ SAFEARRAY** ppRuntimeId) override;
IFACEMETHODIMP get_BoundingRectangle(_Out_ UiaRect* pRect) override;
IFACEMETHODIMP GetEmbeddedFragmentRoots(_Outptr_result_maybenull_ SAFEARRAY** ppRoots) override;
virtual IFACEMETHODIMP SetFocus() = 0;
IFACEMETHODIMP get_FragmentRoot(_COM_Outptr_result_maybenull_ IRawElementProviderFragmentRoot** ppProvider);
IFACEMETHODIMP get_FragmentRoot(_COM_Outptr_result_maybenull_ IRawElementProviderFragmentRoot** ppProvider) override;
// IRawElementProviderFragmentRoot methods
virtual IFACEMETHODIMP ElementProviderFromPoint(_In_ double x,

View file

@ -44,15 +44,15 @@ static const WORD leftShiftScanCode = 0x2A;
size_t cchNeeded;
THROW_IF_FAILED(IntToSizeT(iTarget, &cchNeeded));
// Allocate ourselves space in a smart pointer.
std::unique_ptr<wchar_t[]> pwsOut = std::make_unique<wchar_t[]>(cchNeeded);
THROW_IF_NULL_ALLOC(pwsOut);
// Allocate ourselves some space
std::wstring out;
out.resize(cchNeeded);
// Attempt conversion for real.
THROW_LAST_ERROR_IF(0 == MultiByteToWideChar(codePage, 0, source.data(), iSource, pwsOut.get(), iTarget));
THROW_LAST_ERROR_IF(0 == MultiByteToWideChar(codePage, 0, source.data(), iSource, out.data(), iTarget));
// Return as a string
return std::wstring(pwsOut.get(), cchNeeded);
return out;
}
// Routine Description:
@ -85,18 +85,18 @@ static const WORD leftShiftScanCode = 0x2A;
size_t cchNeeded;
THROW_IF_FAILED(IntToSizeT(iTarget, &cchNeeded));
// Allocate ourselves space in a smart pointer
std::unique_ptr<char[]> psOut = std::make_unique<char[]>(cchNeeded);
THROW_IF_NULL_ALLOC(psOut.get());
// Allocate ourselves some space
std::string out;
out.resize(cchNeeded);
// Attempt conversion for real.
// clang-format off
#pragma prefast(suppress: __WARNING_W2A_BEST_FIT, "WC_NO_BEST_FIT_CHARS doesn't work in many codepages. Retain old behavior.")
// clang-format on
THROW_LAST_ERROR_IF(0 == WideCharToMultiByte(codepage, 0, source.data(), iSource, psOut.get(), iTarget, nullptr, nullptr));
THROW_LAST_ERROR_IF(0 == WideCharToMultiByte(codepage, 0, source.data(), iSource, out.data(), iTarget, nullptr, nullptr));
// Return as a string
return std::string(psOut.get(), cchNeeded);
return out;
}
// Routine Description:
@ -284,7 +284,7 @@ std::deque<std::unique_ptr<KeyEvent>> SynthesizeNumpadEvents(const wchar_t wch,
// But it is absolutely valid as 0xFF or 255 unsigned as the correct CP437 character.
// We need to treat it as unsigned because we're going to pretend it was a keypad entry
// and you don't enter negative numbers on the keypad.
unsigned char const uch = static_cast<unsigned char>(convertedChars[0]);
unsigned char const uch = static_cast<unsigned char>(convertedChars.at(0));
// unsigned char values are in the range [0, 255] so we need to be
// able to store up to 4 chars from the conversion (including the end of string char)

View file

@ -23,13 +23,14 @@ static_assert(sizeof(unsigned int) == sizeof(wchar_t) * 2,
class CodepointWidthDetector final
{
public:
CodepointWidthDetector() = default;
CodepointWidthDetector() noexcept;
CodepointWidthDetector(const CodepointWidthDetector&) = delete;
CodepointWidthDetector(CodepointWidthDetector&&) = delete;
~CodepointWidthDetector() = default;
CodepointWidthDetector& operator=(const CodepointWidthDetector&) = delete;
CodepointWidthDetector& operator=(CodepointWidthDetector&&) = delete;
CodepointWidth GetWidth(const std::wstring_view glyph) const noexcept;
CodepointWidth GetWidth(const std::wstring_view glyph) const;
bool IsWide(const std::wstring_view glyph) const;
bool IsWide(const wchar_t wch) const noexcept;
void SetFallbackMethod(std::function<bool(const std::wstring_view)> pfnFallback);

View file

@ -13,6 +13,6 @@ Abstract:
#include <string_view>
bool IsGlyphFullWidth(const std::wstring_view glyph);
bool IsGlyphFullWidth(const wchar_t wch);
bool IsGlyphFullWidth(const wchar_t wch) noexcept;
void SetGlyphWidthFallback(std::function<bool(std::wstring_view)> pfnFallback);
void NotifyGlyphWidthFontChanged();
void NotifyGlyphWidthFontChanged() noexcept;

View file

@ -245,7 +245,7 @@ public:
void SetActiveModifierKeys(const DWORD activeModifierKeys) noexcept;
void DeactivateModifierKey(const ModifierKeyState modifierKey) noexcept;
void ActivateModifierKey(const ModifierKeyState modifierKey) noexcept;
bool DoActiveModifierKeysMatch(const std::unordered_set<ModifierKeyState>& consoleModifiers) const noexcept;
bool DoActiveModifierKeysMatch(const std::unordered_set<ModifierKeyState>& consoleModifiers) const;
bool IsCommandLineEditingKey() const noexcept;
bool IsPopupKey() const noexcept;

View file

@ -27,7 +27,7 @@ Author(s):
class UTF8OutPipeReader final
{
public:
UTF8OutPipeReader(HANDLE outPipe);
UTF8OutPipeReader(HANDLE outPipe) noexcept;
[[nodiscard]] HRESULT Read(_Out_ std::string_view& strView);
private:
@ -46,7 +46,7 @@ private:
};
// array of bitmasks
constexpr const static BYTE _cmpMasks[]{
constexpr static std::array<BYTE, 4> _cmpMasks{
0, // unused
_Utf8BitMasks::MaskContinuationByte,
_Utf8BitMasks::MaskLeadByteTwoByteSequence,
@ -54,7 +54,7 @@ private:
};
// array of values for the comparisons
constexpr const static BYTE _cmpOperands[]{
constexpr static std::array<BYTE, 4> _cmpOperands{
0, // unused
_Utf8BitMasks::IsAsciiByte, // intentionally conflicts with MaskContinuationByte
_Utf8BitMasks::IsLeadByteTwoByteSequence,
@ -62,7 +62,7 @@ private:
};
HANDLE _outPipe; // non-owning reference to a pipe.
BYTE _buffer[4096]{ 0 }; // buffer for the chunk read
BYTE _utf8Partials[4]{ 0 }; // buffer for code units of a partial UTF-8 code point that have to be cached
std::array<char, 4096> _buffer; // buffer for the chunk read.
std::array<char, 4> _utf8Partials; // buffer for code units of a partial UTF-8 code point that have to be cached
DWORD _dwPartialsLen{}; // number of cached UTF-8 code units
};

View file

@ -28,7 +28,7 @@ private:
public:
static std::vector<std::vector<wchar_t>> Parse(std::wstring_view wstr);
static std::wstring_view ParseNext(std::wstring_view wstr);
static std::wstring_view ParseNext(std::wstring_view wstr) noexcept;
// Routine Description:
// - checks if wchar is a utf16 leading surrogate

View file

@ -15,7 +15,19 @@ namespace Microsoft::Console::Utils
{
bool IsValidHandle(const HANDLE handle) noexcept;
short ClampToShortMax(const long value, const short min);
// Function Description:
// - Clamps a long in between `min` and `SHRT_MAX`
// Arguments:
// - value: the value to clamp
// - min: the minimum value to clamp to
// Return Value:
// - The clamped value as a short.
constexpr short ClampToShortMax(const long value, const short min) noexcept
{
return static_cast<short>(std::clamp(value,
static_cast<long>(min),
static_cast<long>(SHRT_MAX)));
}
std::wstring GuidToString(const GUID guid);
GUID GuidFromString(const std::wstring wstr);
@ -24,11 +36,26 @@ namespace Microsoft::Console::Utils
std::string ColorToHexString(const COLORREF color);
COLORREF ColorFromHexString(const std::string wstr);
void InitializeCampbellColorTable(gsl::span<COLORREF>& table);
void InitializeCampbellColorTableForConhost(gsl::span<COLORREF>& table);
void SwapANSIColorOrderForConhost(gsl::span<COLORREF>& table);
void Initialize256ColorTable(gsl::span<COLORREF>& table);
void SetColorTableAlpha(gsl::span<COLORREF>& table, const BYTE newAlpha);
void InitializeCampbellColorTable(const gsl::span<COLORREF> table);
void InitializeCampbellColorTableForConhost(const gsl::span<COLORREF> table);
void SwapANSIColorOrderForConhost(const gsl::span<COLORREF> table);
void Initialize256ColorTable(const gsl::span<COLORREF> table);
// Function Description:
// - Fill the alpha byte of the colors in a given color table with the given value.
// Arguments:
// - table: a color table
// - newAlpha: the new value to use as the alpha for all the entries in that table.
// Return Value:
// - <none>
constexpr void SetColorTableAlpha(const gsl::span<COLORREF> table, const BYTE newAlpha) noexcept
{
const auto shiftedAlpha = newAlpha << 24;
for (auto& color : table)
{
WI_UpdateFlagsInMask(color, 0xff000000, shiftedAlpha);
}
}
constexpr uint16_t EndianSwap(uint16_t value)
{
@ -46,7 +73,7 @@ namespace Microsoft::Console::Utils
constexpr unsigned long EndianSwap(unsigned long value)
{
return static_cast<unsigned long>(EndianSwap(static_cast<uint32_t>(value)));
return gsl::narrow_cast<unsigned long>(EndianSwap(gsl::narrow_cast<uint32_t>(value)));
}
constexpr GUID EndianSwap(GUID value)
@ -57,5 +84,5 @@ namespace Microsoft::Console::Utils
return value;
}
GUID CreateV5Uuid(const GUID& namespaceGuid, const gsl::span<const gsl::byte>& name);
GUID CreateV5Uuid(const GUID& namespaceGuid, const gsl::span<const gsl::byte> name);
}

View file

@ -59,7 +59,7 @@ namespace Microsoft::Console::Types
bool IsInBounds(const COORD& pos) const noexcept;
void Clamp(COORD& pos) const;
Viewport Clamp(const Viewport& other) const;
Viewport Clamp(const Viewport& other) const noexcept;
bool MoveInBounds(const ptrdiff_t move, COORD& pos) const noexcept;
bool IncrementInBounds(COORD& pos) const noexcept;

View file

@ -52,11 +52,11 @@ void UtilsTests::TestSwapColorPalette()
std::array<COLORREF, COLOR_TABLE_SIZE> consoleTable;
gsl::span<COLORREF> terminalTableView = { &terminalTable[0], gsl::narrow<ptrdiff_t>(terminalTable.size()) };
gsl::span<COLORREF> consoleTableleView = { &consoleTable[0], gsl::narrow<ptrdiff_t>(consoleTable.size()) };
gsl::span<COLORREF> consoleTableView = { &consoleTable[0], gsl::narrow<ptrdiff_t>(consoleTable.size()) };
// First set up the colors
InitializeCampbellColorTable(terminalTableView);
InitializeCampbellColorTableForConhost(consoleTableleView);
InitializeCampbellColorTableForConhost(consoleTableView);
VERIFY_ARE_EQUAL(terminalTable[0], consoleTable[0]);
VERIFY_ARE_EQUAL(terminalTable[1], consoleTable[4]);

View file

@ -6,20 +6,6 @@
using namespace Microsoft::Console;
// Function Description:
// - Clamps a long in between `min` and `SHRT_MAX`
// Arguments:
// - value: the value to clamp
// - min: the minimum value to clamp to
// Return Value:
// - The clamped value as a short.
short Utils::ClampToShortMax(const long value, const short min)
{
return static_cast<short>(std::clamp(value,
static_cast<long>(min),
static_cast<long>(SHRT_MAX)));
}
// Function Description:
// - Creates a String representation of a guid, in the format
// "{12345678-ABCD-EF12-3456-7890ABCDEF12}"
@ -29,12 +15,12 @@ short Utils::ClampToShortMax(const long value, const short min)
// - a string representation of the GUID. On failure, throws E_INVALIDARG.
std::wstring Utils::GuidToString(const GUID guid)
{
wchar_t guid_cstr[39];
const int written = swprintf(guid_cstr, sizeof(guid_cstr), L"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
std::array<wchar_t, 39> guid_cstr;
const int written = swprintf(guid_cstr.data(), guid_cstr.size(), L"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
THROW_HR_IF(E_INVALIDARG, written == -1);
return std::wstring(guid_cstr);
return std::wstring(guid_cstr.data(), guid_cstr.size());
}
// Method Description:
@ -92,7 +78,7 @@ std::string Utils::ColorToHexString(const COLORREF color)
COLORREF Utils::ColorFromHexString(const std::string str)
{
THROW_HR_IF(E_INVALIDARG, str.size() != 7 && str.size() != 4);
THROW_HR_IF(E_INVALIDARG, str[0] != '#');
THROW_HR_IF(E_INVALIDARG, str.at(0) != '#');
std::string rStr;
std::string gStr;
@ -100,20 +86,20 @@ COLORREF Utils::ColorFromHexString(const std::string str)
if (str.size() == 4)
{
rStr = std::string(2, str[1]);
gStr = std::string(2, str[2]);
bStr = std::string(2, str[3]);
rStr = std::string(2, str.at(1));
gStr = std::string(2, str.at(2));
bStr = std::string(2, str.at(3));
}
else
{
rStr = std::string(&str[1], 2);
gStr = std::string(&str[3], 2);
bStr = std::string(&str[5], 2);
rStr = std::string(&str.at(1), 2);
gStr = std::string(&str.at(3), 2);
bStr = std::string(&str.at(5), 2);
}
BYTE r = static_cast<BYTE>(std::stoul(rStr, nullptr, 16));
BYTE g = static_cast<BYTE>(std::stoul(gStr, nullptr, 16));
BYTE b = static_cast<BYTE>(std::stoul(bStr, nullptr, 16));
const BYTE r = gsl::narrow_cast<BYTE>(std::stoul(rStr, nullptr, 16));
const BYTE g = gsl::narrow_cast<BYTE>(std::stoul(gStr, nullptr, 16));
const BYTE b = gsl::narrow_cast<BYTE>(std::stoul(bStr, nullptr, 16));
return RGB(r, g, b);
}
@ -126,7 +112,7 @@ COLORREF Utils::ColorFromHexString(const std::string str)
// - True if non zero and not set to invalid magic value. False otherwise.
bool Utils::IsValidHandle(const HANDLE handle) noexcept
{
return handle != 0 && handle != INVALID_HANDLE_VALUE;
return handle != nullptr && handle != INVALID_HANDLE_VALUE;
}
// Function Description:
@ -136,7 +122,7 @@ bool Utils::IsValidHandle(const HANDLE handle) noexcept
// - table: a color table with at least 16 entries
// Return Value:
// - <none>, throws if the table has less that 16 entries
void Utils::InitializeCampbellColorTable(gsl::span<COLORREF>& table)
void Utils::InitializeCampbellColorTable(const gsl::span<COLORREF> table)
{
THROW_HR_IF(E_INVALIDARG, table.size() < 16);
@ -167,7 +153,7 @@ void Utils::InitializeCampbellColorTable(gsl::span<COLORREF>& table)
// - table: a color table with at least 16 entries
// Return Value:
// - <none>, throws if the table has less that 16 entries
void Utils::InitializeCampbellColorTableForConhost(gsl::span<COLORREF>& table)
void Utils::InitializeCampbellColorTableForConhost(const gsl::span<COLORREF> table)
{
THROW_HR_IF(E_INVALIDARG, table.size() < 16);
InitializeCampbellColorTable(table);
@ -180,7 +166,7 @@ void Utils::InitializeCampbellColorTableForConhost(gsl::span<COLORREF>& table)
// - table: a color table with at least 16 entries
// Return Value:
// - <none>, throws if the table has less that 16 entries
void Utils::SwapANSIColorOrderForConhost(gsl::span<COLORREF>& table)
void Utils::SwapANSIColorOrderForConhost(const gsl::span<COLORREF> table)
{
THROW_HR_IF(E_INVALIDARG, table.size() < 16);
std::swap(table[1], table[4]);
@ -196,7 +182,7 @@ void Utils::SwapANSIColorOrderForConhost(gsl::span<COLORREF>& table)
// - table: a color table with at least 256 entries
// Return Value:
// - <none>, throws if the table has less that 256 entries
void Utils::Initialize256ColorTable(gsl::span<COLORREF>& table)
void Utils::Initialize256ColorTable(const gsl::span<COLORREF> table)
{
THROW_HR_IF(E_INVALIDARG, table.size() < 256);
@ -460,22 +446,6 @@ void Utils::Initialize256ColorTable(gsl::span<COLORREF>& table)
// clang-format on
}
// Function Description:
// - Fill the alpha byte of the colors in a given color table with the given value.
// Arguments:
// - table: a color table
// - newAlpha: the new value to use as the alpha for all the entries in that table.
// Return Value:
// - <none>
void Utils::SetColorTableAlpha(gsl::span<COLORREF>& table, const BYTE newAlpha)
{
const auto shiftedAlpha = newAlpha << 24;
for (auto& color : table)
{
WI_UpdateFlagsInMask(color, 0xff000000, shiftedAlpha);
}
}
// Function Description:
// - Generate a Version 5 UUID (specified in RFC4122 4.3)
// v5 UUIDs are stable given the same namespace and "name".
@ -486,7 +456,7 @@ void Utils::SetColorTableAlpha(gsl::span<COLORREF>& table, const BYTE newAlpha)
// - name: Bytes comprising the name (in a namespace-specific format)
// Return Value:
// - a new stable v5 UUID
GUID Utils::CreateV5Uuid(const GUID& namespaceGuid, const gsl::span<const gsl::byte>& name)
GUID Utils::CreateV5Uuid(const GUID& namespaceGuid, const gsl::span<const gsl::byte> name)
{
// v5 uuid generation happens over values in network byte order, so let's enforce that
auto correctEndianNamespaceGuid{ EndianSwap(namespaceGuid) };
@ -503,8 +473,8 @@ GUID Utils::CreateV5Uuid(const GUID& namespaceGuid, const gsl::span<const gsl::b
std::array<uint8_t, 20> buffer;
THROW_IF_NTSTATUS_FAILED(BCryptFinishHash(hash.get(), buffer.data(), gsl::narrow<ULONG>(buffer.size()), 0));
buffer[6] = (buffer[6] & 0x0F) | 0x50; // set the uuid version to 5
buffer[8] = (buffer[8] & 0x3F) | 0x80; // set the variant to 2 (RFC4122)
buffer.at(6) = (buffer.at(6) & 0x0F) | 0x50; // set the uuid version to 5
buffer.at(8) = (buffer.at(8) & 0x3F) | 0x80; // set the variant to 2 (RFC4122)
// We're using memcpy here pursuant to N4713 6.7.2/3 [basic.types],
// "...the underlying bytes making up the object can be copied into an array

View file

@ -194,7 +194,7 @@ void Viewport::Clamp(COORD& pos) const
// - other - Viewport to clamp to the inside of this viewport
// Return Value:
// - Clamped viewport
Viewport Viewport::Clamp(const Viewport& other) const
Viewport Viewport::Clamp(const Viewport& other) const noexcept
{
auto clampMe = other.ToInclusive();
@ -450,7 +450,7 @@ bool Viewport::WalkInBoundsCircular(COORD& pos, const WalkDir dir) const noexcep
// if using this same viewport with the `WalkInBounds` methods.
COORD Viewport::GetWalkOrigin(const WalkDir dir) const noexcept
{
COORD origin;
COORD origin{ 0 };
origin.X = dir.x == XWalk::LeftToRight ? Left() : RightInclusive();
origin.Y = dir.y == YWalk::TopToBottom ? Top() : BottomInclusive();
return origin;