Fix coloring of BitmapText with overlapping attributes

When AddAttribute() is called multiple times with overlapping ranges, old
attributes need to be removed and/or fixed. Otherwise the old colors might
show up when the text is rendered.
This commit is contained in:
phantom10111
2024-04-09 08:00:44 +02:00
committed by teejusb
parent 17c4e7a2ff
commit 208494b735
+45 -2
View File
@@ -880,7 +880,7 @@ void BitmapText::AddAttribute( std::size_t iPos, const Attribute &attr )
{
// Fixup position for new lines.
Attribute newAttr = attr;
std::vector<std::wstring>::const_iterator lineIter = m_wTextLines.cbegin();
auto lineIter = m_wTextLines.cbegin();
int iLines = 0;
std::size_t iAdjustedPos = iPos;
@@ -911,7 +911,50 @@ void BitmapText::AddAttribute( std::size_t iPos, const Attribute &attr )
if( newAttr.length == 0 ) // Attribute doesn't cover any printable characters
return;
m_mAttributes[iPos-iLines] = newAttr;
// Check if there are existing attributes overlapping this one. We might need to remove or fix them up.
const std::size_t iStartPos = iPos - iLines;
const std::size_t iEndPos = iStartPos + newAttr.length;
// First attribute starting at the same position or further than the new attribute
const auto iterFirstAfterStart = m_mAttributes.lower_bound( iStartPos );
if( iterFirstAfterStart != m_mAttributes.begin() )
{
// Last attribute starting at earlier position than the new attribute (if it exists)
auto iterLastBeforeStart = iterFirstAfterStart;
--iterLastBeforeStart;
// Fixup the length so that it ends before the new attribute
iterLastBeforeStart->second.length = std::min( iterLastBeforeStart->second.length, static_cast<int>(iStartPos - iterLastBeforeStart->first) );
}
// First attribute starting after the end of the new attribute
auto iterLastBeforeEnd = m_mAttributes.lower_bound( iEndPos );
if( iterLastBeforeEnd != iterFirstAfterStart )
{
// Go back one, so that we are at the last overlapping attribute
--iterLastBeforeEnd;
const bool lastAttrOverlappingCompletely = iterLastBeforeEnd->first + iterLastBeforeEnd->second.length <= iEndPos;
auto iterEraseEnd = iterLastBeforeEnd;
// If it's overlapping completely, erase it as well
if( lastAttrOverlappingCompletely )
++iterEraseEnd;
m_mAttributes.erase( iterFirstAfterStart, iterEraseEnd );
// Otherwise it's only overlapping partially so fix it up
if( !lastAttrOverlappingCompletely )
{
// Fixup the length accordingly
Attribute lastAttr = iterLastBeforeEnd->second;
lastAttr.length -= iEndPos - iterLastBeforeEnd->first;
// Erase it and insert just after the new attribute
m_mAttributes.erase( iterLastBeforeEnd );
m_mAttributes[iEndPos] = lastAttr;
}
}
m_mAttributes[iStartPos] = newAttr;
m_bHasGlowAttribute = m_bHasGlowAttribute || attr.glow.a > 0.0001f;
}