Skip to content

Commit

Permalink
Fix justification broken due to line width mis-computation
Browse files Browse the repository at this point in the history
  • Loading branch information
nieznanysprawiciel committed Nov 13, 2024
1 parent b7166e3 commit f875d25
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 33 deletions.
2 changes: 1 addition & 1 deletion swGUI/Prototypes/TextShowcase/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ void AddControls ( HostWindow* host )
auto pen = std::make_shared< ImageBrush >();
pen->SetTexture( "$(Application-Dir)/pool-water-texture.jpg" );

auto background = std::make_shared< SolidColorBrush >( Colors::WhiteSmoke );
auto background = std::make_shared< SolidColorBrush >( Colors::Transparent );
auto textBlock = AddText( host, background, pen, 300, 300, Position( 400, 450 ), sLoremIpsum );
textBlock->SetTextAlignment( sw::TextAlignment::Justify );
}
Expand Down
83 changes: 61 additions & 22 deletions swGraphicAPI/Assets/TextAsset/Text.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,12 @@ void TextArranger::ApplyAlignement( const FontLayout& layout, std
case TextAlignment::Justify:
{
// Find all spaces which will be extended.
auto numSpaces = std::count_if( text.begin(), text.begin() + lastCharIdx, [](wchar_t c) { return IsWhitespace(c); });
auto numSpaces = std::count_if( text.begin(), text.begin() + lastCharIdx, [](wchar_t c) { return IsWhitespace(c); });
auto trailingSpaces = CountTrailingWhitespaces( std::wstring_view( text.data(), lastCharIdx ) );

// Distribute remaining space equally between all spaces.
// (Besides last one: we have one place less between than number of chars)
float offsetPerSpace = remainingSpace / ( numSpaces - 1 );
float offsetPerSpace = remainingSpace / ( numSpaces - trailingSpaces );
float curOffset = 0.0f;

for( Size i = 0; i < letters.size(); i++ )
Expand All @@ -175,28 +176,18 @@ void TextArranger::ApplyAlignement( const FontLayout& layout, std

float TextArranger::TextWidth( const std::vector< Position2d >& letters, const std::wstring& text, const FontLayout& layout ) const
{
Size charIdx = letters.size() - 1;
Position2d last = letters[ charIdx ];
float adjustLast = 0.0;
Size lastCharIdx = letters.size() - 1;
Size trailingSpaces = CountTrailingWhitespaces( std::wstring_view( text.c_str(), letters.size() ) );
i64 lastNonSpace = (i64)lastCharIdx - (i64)trailingSpaces;

if( IsSpace( text[ charIdx ] ) )
{
// If last character was space, we want to adjust to last character before.
adjustLast = -( this->SpaceSize + this->Interspace );
}
else if( IsNewline( text[ charIdx ] ) )
{
// Ignore newline, since last character is already in correct position.
float adjustLast = 0.0;
}
else
{
// Normal character. We need to move forward to right edge.
auto& glyph = layout.Glyphs.at( text[ charIdx ] );
adjustLast = (float)glyph.Width - (float)glyph.BearingX;
}
if( lastNonSpace < 0 )
return 0.0f; // No characters in text (only spaces or newlines)

return letters.back().x - letters.front().x + adjustLast;
// We need to find right edge of the last non whitespace character in line.
auto lastRightEdge = TopRightVertex( layout.Glyphs.at( text[ lastNonSpace ] ), letters[ lastNonSpace ] ).x;
auto firstLeftEdge = TopLeftVertex( layout.Glyphs.at( text[ 0 ] ), letters[ 0 ] ).x;

return lastRightEdge - firstLeftEdge;
}

// ================================ //
Expand Down Expand Up @@ -256,6 +247,54 @@ Rect2d TextArranger::ComputeTextBounds( const std::vector< Position

// ================================ //

Size TextArranger::CountTrailingWhitespaces( const std::wstring_view& text )
{
for( auto iter = text.rbegin(); iter != text.rend(); iter++ )
{
if( !IsWhitespace( *iter ) )
return std::distance( text.rbegin(), iter );
}

return 0;
}

// ================================ //

Position2d TextArranger::TopLeftVertex( const Glyph& glyph, Position2d position )
{
Position2d bearing = Position2d( (float)glyph.BearingX, (float)glyph.BearingY );
return position + bearing;
}

// ================================ //

Position2d TextArranger::TopRightVertex( const Glyph& glyph, Position2d position )
{
Position2d bearing = Position2d( (float)glyph.BearingX, (float)glyph.BearingY );
Position2d quadTopRight = Position2d( (float)glyph.Width, 0.f );
return quadTopRight + position + bearing;
}

// ================================ //

Position2d TextArranger::BottomLeftVertex( const Glyph& glyph, Position2d position )
{
Position2d bearing = Position2d( (float)glyph.BearingX, (float)glyph.BearingY );
Position2d quadBottomLeft = Position2d( 0.f, -(float)glyph.Height );
return quadBottomLeft + position + bearing;
}

// ================================ //

Position2d TextArranger::BottomRightVertex( const Glyph& glyph, Position2d position )
{
Position2d bearing = Position2d( (float)glyph.BearingX, (float)glyph.BearingY );
Position2d quadBottomRight = Position2d( (float)glyph.Width, -(float)glyph.Height );
return quadBottomRight + position + bearing;
}

// ================================ //

Nullable< geom::IndexedGeometryBuffer< geom::VertexShape2D, Index32 > >
TextArranger::GenerateGeometry( const std::wstring& text, const FontAssetPtr font, bool genBackground ) const
{
Expand Down
6 changes: 6 additions & 0 deletions swGraphicAPI/Assets/TextAsset/Text.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ class TextArranger
static bool IsSpace( wchar_t character );
static Size EstimateLineLength( std::wstring_view text );
static Rect2d ComputeTextBounds( const std::vector< Position2d >& letters );
static Size CountTrailingWhitespaces( const std::wstring_view& text );

static Position2d TopLeftVertex( const Glyph& glyph, Position2d pos );
static Position2d TopRightVertex( const Glyph& glyph, Position2d pos );
static Position2d BottomLeftVertex( const Glyph& glyph, Position2d pos );
static Position2d BottomRightVertex( const Glyph& glyph, Position2d pos );

public:
Nullable< geom::IndexedGeometryBuffer< geom::VertexShape2D, Index32 > > GenerateGeometry( const std::wstring& text, const FontAssetPtr font, bool genBackground ) const;
Expand Down
14 changes: 4 additions & 10 deletions swGraphicAPI/Assets/TextAsset/Text.inl
Original file line number Diff line number Diff line change
Expand Up @@ -147,25 +147,19 @@ inline void
TextGeometryGenerator< VertexType, IndexType, TextAcc >::PutLetterVertex( VertexType& vertex, const Glyph& glyph,
Position2d position, Size vertexIdx ) const
{
Position2d bearing = Position2d( (float)glyph.BearingX, (float)glyph.BearingY );

switch ( vertexIdx % 4 )
{
case 0:
Position2d quadTopLeft = Position2d( 0.f, 0.f );
TextAcc::GetPos( vertex ) = quadTopLeft + position + bearing;
TextAcc::GetPos( vertex ) = TextArranger::TopLeftVertex( glyph, position );
break;
case 1:
Position2d quadTopRight = Position2d( (float)glyph.Width, 0.f );
TextAcc::GetPos( vertex ) = quadTopRight + position + bearing;
TextAcc::GetPos( vertex ) = TextArranger::TopRightVertex( glyph, position );
break;
case 2:
Position2d quadBottomLeft = Position2d( 0.f, -(float)glyph.Height );
TextAcc::GetPos( vertex ) = quadBottomLeft + position + bearing;
TextAcc::GetPos( vertex ) = TextArranger::BottomLeftVertex( glyph, position );
break;
case 3:
Position2d quadBottomRight = Position2d( (float)glyph.Width, -(float)glyph.Height );
TextAcc::GetPos( vertex ) = quadBottomRight + position + bearing;
TextAcc::GetPos( vertex ) = TextArranger::BottomRightVertex( glyph, position );
break;
}
}
Expand Down

0 comments on commit f875d25

Please sign in to comment.