mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-08-18 06:55:48 +03:00
Fixes for line widths calculation.
This commit is contained in:
@@ -64,14 +64,14 @@ Float LineWrap::computeOffsets( const String::View& string, Font* font, Uint32 c
|
||||
return 0.f;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T LineWrap::computeLineBreaksInternal( const String::View& string, Font* font, Uint32 characterSize,
|
||||
Float maxWidth, LineWrapMode mode, Uint32 fontStyle,
|
||||
Float outlineThickness, bool keepIndentation,
|
||||
Uint32 tabWidth,
|
||||
Float whiteSpaceWidth /* 0 = should calculate it */,
|
||||
Uint32 textDrawHints, bool tabStops, Float initialXOffset ) {
|
||||
T info;
|
||||
template <typename LineWrapType>
|
||||
LineWrapType
|
||||
LineWrap::computeLineBreaksInternal( const String::View& string, Font* font, Uint32 characterSize,
|
||||
Float maxWidth, LineWrapMode mode, Uint32 fontStyle,
|
||||
Float outlineThickness, bool keepIndentation, Uint32 tabWidth,
|
||||
Float whiteSpaceWidth /* 0 = should calculate it */,
|
||||
Uint32 textDrawHints, bool tabStops, Float initialXOffset ) {
|
||||
LineWrapType info;
|
||||
info.wraps.push_back( 0 );
|
||||
|
||||
if ( string.empty() || nullptr == font || mode == LineWrapMode::NoWrap || maxWidth == 0 )
|
||||
@@ -84,7 +84,7 @@ T LineWrap::computeLineBreaksInternal( const String::View& string, Font* font, U
|
||||
string, font, characterSize, fontStyle, tabWidth, outlineThickness,
|
||||
tabStops ? initialXOffset : std::optional<Float>{}, textDrawHints,
|
||||
TextDirection::LeftToRight, mode, maxWidth, keepIndentation, initialXOffset );
|
||||
T info;
|
||||
LineWrapType info;
|
||||
if ( layout->paragraphs.empty() )
|
||||
return info;
|
||||
|
||||
@@ -101,7 +101,7 @@ T LineWrap::computeLineBreaksInternal( const String::View& string, Font* font, U
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr ( std::is_same_v<T, LineWrapInfoEx> ) {
|
||||
if constexpr ( std::is_same_v<LineWrapType, LineWrapInfoEx> ) {
|
||||
for ( auto& paragraph : layout->paragraphs ) {
|
||||
for ( const auto& wrapWidth : paragraph.wrapInfo.wrapsWidth ) {
|
||||
info.wrapsWidth.push_back( wrapWidth );
|
||||
@@ -142,16 +142,21 @@ T LineWrap::computeLineBreaksInternal( const String::View& string, Font* font, U
|
||||
|
||||
for ( const auto& curChar : string ) {
|
||||
if ( curChar == '\n' ) {
|
||||
if constexpr ( std::is_same_v<T, LineWrapInfoEx> ) {
|
||||
info.wrapsWidth.back() = xoffset; // Finalize width of current line
|
||||
if constexpr ( std::is_same_v<LineWrapType, LineWrapInfoEx> ) {
|
||||
if ( info.wrapsWidth.empty() )
|
||||
info.wrapsWidth.push_back( std::ceil( xoffset ) );
|
||||
else
|
||||
info.wrapsWidth.back() = std::ceil( xoffset ); // Finalize width of current line
|
||||
}
|
||||
xoffset = 0;
|
||||
if constexpr ( std::is_same_v<T, LineWrapInfoEx> ) {
|
||||
info.wrapsWidth.push_back( 0.f ); // Placeholder for new line's width
|
||||
if constexpr ( std::is_same_v<LineWrapType, LineWrapInfoEx> ) {
|
||||
if ( idx + 1 != string.size() )
|
||||
info.wrapsWidth.push_back( 0.f ); // Placeholder for new line's width
|
||||
}
|
||||
lastSpace = idx;
|
||||
info.wraps.push_back( lastSpace );
|
||||
idx++;
|
||||
prevChar = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -175,26 +180,35 @@ T LineWrap::computeLineBreaksInternal( const String::View& string, Font* font, U
|
||||
|
||||
if ( xoffset > maxWidth ) {
|
||||
if ( mode == LineWrapMode::Word && lastSpace ) {
|
||||
if constexpr ( std::is_same_v<T, LineWrapInfoEx> ) {
|
||||
info.wrapsWidth.back() = lastWordWrapWidth;
|
||||
if constexpr ( std::is_same_v<LineWrapType, LineWrapInfoEx> ) {
|
||||
if ( info.wrapsWidth.empty() )
|
||||
info.wrapsWidth.push_back( std::ceil( lastWordWrapWidth ) );
|
||||
else
|
||||
info.wrapsWidth.back() = std::ceil( lastWordWrapWidth );
|
||||
}
|
||||
|
||||
info.wraps.push_back( lastSpace + 1 );
|
||||
|
||||
if constexpr ( std::is_same_v<T, LineWrapInfoEx> ) {
|
||||
info.wrapsWidth.push_back( 0.f );
|
||||
if constexpr ( std::is_same_v<LineWrapType, LineWrapInfoEx> ) {
|
||||
if ( idx + 1 != string.size() )
|
||||
info.wrapsWidth.push_back( 0.f );
|
||||
}
|
||||
|
||||
xoffset = info.paddingStart + ( xoffset - lastWidth );
|
||||
} else {
|
||||
if constexpr ( std::is_same_v<T, LineWrapInfoEx> ) {
|
||||
info.wrapsWidth.back() = xoffset - w; // Width up to char *before* current one
|
||||
if constexpr ( std::is_same_v<LineWrapType, LineWrapInfoEx> ) {
|
||||
// Width up to char *before* current one
|
||||
if ( info.wrapsWidth.empty() )
|
||||
info.wrapsWidth.push_back( std::ceil( xoffset - w ) );
|
||||
else
|
||||
info.wrapsWidth.back() = std::ceil( xoffset - w );
|
||||
}
|
||||
|
||||
info.wraps.push_back( idx );
|
||||
|
||||
if constexpr ( std::is_same_v<T, LineWrapInfoEx> ) {
|
||||
info.wrapsWidth.push_back( 0.f );
|
||||
if constexpr ( std::is_same_v<LineWrapType, LineWrapInfoEx> ) {
|
||||
if ( idx + 1 != string.size() )
|
||||
info.wrapsWidth.push_back( 0.f );
|
||||
}
|
||||
|
||||
xoffset = info.paddingStart;
|
||||
@@ -210,10 +224,9 @@ T LineWrap::computeLineBreaksInternal( const String::View& string, Font* font, U
|
||||
idx++;
|
||||
}
|
||||
|
||||
if constexpr ( std::is_same_v<T, LineWrapInfoEx> ) {
|
||||
if ( !info.wrapsWidth.empty() ) { // Ensure there's at least one line
|
||||
info.wrapsWidth.back() = xoffset;
|
||||
}
|
||||
if constexpr ( std::is_same_v<LineWrapType, LineWrapInfoEx> ) {
|
||||
if ( !string.empty() && string[string.size() - 1] != '\n' && !info.wrapsWidth.empty() )
|
||||
info.wrapsWidth.back() = std::ceil( xoffset );
|
||||
}
|
||||
|
||||
return info;
|
||||
|
||||
@@ -420,7 +420,8 @@ TextLayout::Cache TextLayout::layout( const String::View& string, Font* font,
|
||||
|
||||
if ( run.runIsNewLine() ) {
|
||||
curParagraph->size.x = std::ceil( pen.x );
|
||||
curParagraph->wrapInfo.wrapsWidth.push_back( curParagraph->size.x );
|
||||
curParagraph->wrapInfo.wrapsWidth.push_back(
|
||||
std::ceil( curParagraph->size.x ) );
|
||||
maxWidth = eemax( maxWidth, curParagraph->size.x );
|
||||
pen.x = 0;
|
||||
pen.y += vspace;
|
||||
@@ -440,7 +441,7 @@ TextLayout::Cache TextLayout::layout( const String::View& string, Font* font,
|
||||
Uint32 curChar = string[i];
|
||||
if ( curChar == '\n' ) {
|
||||
curParagraph->size.x = std::ceil( pen.x );
|
||||
curParagraph->wrapInfo.wrapsWidth.push_back( curParagraph->size.x );
|
||||
curParagraph->wrapInfo.wrapsWidth.push_back( std::ceil( curParagraph->size.x ) );
|
||||
maxWidth = eemax( maxWidth, pen.x );
|
||||
pen.x = 0;
|
||||
pen.y += vspace;
|
||||
@@ -495,12 +496,12 @@ TextLayout::Cache TextLayout::layout( const String::View& string, Font* font,
|
||||
}
|
||||
|
||||
// pen.y doesn't have the last line height counted unless the last run ended with a new line
|
||||
if ( string[string.size() - 1] != '\n' )
|
||||
if ( string[string.size() - 1] != '\n' ) {
|
||||
pen.y += vspace;
|
||||
|
||||
curParagraph->wrapInfo.wrapsWidth.push_back( std::ceil( curParagraph->size.x ) );
|
||||
}
|
||||
curParagraph->size.x = std::ceil( pen.x );
|
||||
curParagraph->size.y = pen.y;
|
||||
curParagraph->wrapInfo.wrapsWidth.push_back( curParagraph->size.x );
|
||||
maxWidth = eemax( maxWidth, curParagraph->size.x );
|
||||
result.size = { maxWidth, std::ceil( pen.y ) };
|
||||
result.hasMixedDirection = !!gdc.ltr + !!gdc.rtl + !!gdc.ttb + !!gdc.btt + !!gdc.other > 1;
|
||||
@@ -591,7 +592,7 @@ void TextLayout::wrapLayout( const String::View& string, TextLayout& result,
|
||||
ShapedGlyph& breakGlyph = sp.shapedGlyphs[breakIndex];
|
||||
|
||||
sp.wrapInfo.wraps.push_back( breakStringIdx );
|
||||
sp.wrapInfo.wrapsWidth.push_back( breakGlyph.position.x + breakGlyph.advance.x );
|
||||
sp.wrapInfo.wrapsWidth.push_back( std::ceil( breakGlyph.position.x ) );
|
||||
|
||||
Vector2f adjustment( -breakGlyph.position.x + sp.wrapInfo.paddingStart, vspace );
|
||||
for ( std::size_t k = breakIndex; k <= idx; ++k )
|
||||
@@ -612,8 +613,8 @@ void TextLayout::wrapLayout( const String::View& string, TextLayout& result,
|
||||
// Restore the original wraps which are the paragraph wraps (no wrapping occurred)
|
||||
sp.wrapInfo.wrapsWidth = std::move( wrapsWidth );
|
||||
} else if ( !sp.shapedGlyphs.empty() ) {
|
||||
sp.wrapInfo.wrapsWidth.push_back( sp.shapedGlyphs.back().position.x +
|
||||
sp.shapedGlyphs.back().advance.x );
|
||||
sp.wrapInfo.wrapsWidth.push_back(
|
||||
std::ceil( sp.shapedGlyphs.back().position.x + sp.shapedGlyphs.back().advance.x ) );
|
||||
}
|
||||
|
||||
sp.size = maxSize;
|
||||
|
||||
@@ -969,8 +969,6 @@ UTEST( FontRendering, TextLayoutWrap ) {
|
||||
|
||||
UTEST( FontRendering, LineWrapInfo ) {
|
||||
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
||||
std::string string;
|
||||
FileSystem::fileGet( "assets/textfiles/test-hard-wrap.uext", string );
|
||||
|
||||
UIApplication app(
|
||||
WindowSettings( 1024, 650, "eepp - LineWrapInfo Test", WindowStyle::Default,
|
||||
@@ -980,32 +978,67 @@ UTEST( FontRendering, LineWrapInfo ) {
|
||||
|
||||
Font* font = app.getUI()->getUIThemeManager()->getDefaultFont();
|
||||
Float width = app.getWindow()->getSize().getWidth();
|
||||
int fontSize = 16;
|
||||
LineWrapMode mode = LineWrapMode::Word;
|
||||
|
||||
LineWrapInfo lineWrapShaperDisabled;
|
||||
LineWrapInfo lineWrapShaperEnabled;
|
||||
{
|
||||
UTEST_PRINT_STEP( "Text Shaper disabled" );
|
||||
BoolScopedOp op( Text::TextShaperEnabled, false );
|
||||
String str( string );
|
||||
lineWrapShaperDisabled = LineWrap::computeLineBreaks( string, font, 16, width, mode );
|
||||
}
|
||||
const auto runTest = [&]( const std::string& path ) {
|
||||
UTEST_PRINT_STEP( String::format( "Test File: %s", path.c_str() ).c_str() );
|
||||
UTEST_PRINT_STEP( "Line Breaks" );
|
||||
|
||||
UTEST_PRINT_STEP( "Text Shaper enabled" );
|
||||
{
|
||||
BoolScopedOp op( Text::TextShaperEnabled, true );
|
||||
String str( string );
|
||||
lineWrapShaperEnabled = LineWrap::computeLineBreaks( string, font, 16, width, mode );
|
||||
std::string string;
|
||||
FileSystem::fileGet( path, string );
|
||||
LineWrapInfoEx lineWrapShaperDisabled;
|
||||
LineWrapInfoEx lineWrapShaperEnabled;
|
||||
LineWrapInfoEx lineWrapShaperEnabledWOO;
|
||||
|
||||
{
|
||||
UTEST_PRINT_STEP( "Text Shaper enabled w/o optimizations" );
|
||||
BoolScopedOp op2( Text::TextShaperOptimizations, false );
|
||||
UTEST_PRINT_STEP( "Text Shaper disabled" );
|
||||
BoolScopedOp op( Text::TextShaperEnabled, false );
|
||||
String str( string );
|
||||
lineWrapShaperEnabled = LineWrap::computeLineBreaks( string, font, 16, width, mode );
|
||||
lineWrapShaperDisabled =
|
||||
LineWrap::computeLineBreaksEx( string, font, fontSize, width, mode );
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_VECTOREQ( lineWrapShaperDisabled.wraps, lineWrapShaperEnabled.wraps );
|
||||
UTEST_PRINT_STEP( "Text Shaper enabled" );
|
||||
{
|
||||
BoolScopedOp op( Text::TextShaperEnabled, true );
|
||||
String str( string );
|
||||
lineWrapShaperEnabled =
|
||||
LineWrap::computeLineBreaksEx( string, font, fontSize, width, mode );
|
||||
|
||||
EXPECT_VECTOREQ( lineWrapShaperDisabled.wraps, lineWrapShaperEnabled.wraps );
|
||||
|
||||
{
|
||||
UTEST_PRINT_STEP( "Text Shaper enabled w/o optimizations" );
|
||||
BoolScopedOp op2( Text::TextShaperOptimizations, false );
|
||||
String str( string );
|
||||
lineWrapShaperEnabledWOO =
|
||||
LineWrap::computeLineBreaksEx( string, font, fontSize, width, mode );
|
||||
EXPECT_VECTOREQ( lineWrapShaperDisabled.wraps, lineWrapShaperEnabledWOO.wraps );
|
||||
}
|
||||
}
|
||||
|
||||
UTEST_PRINT_STEP( "Test Widths" );
|
||||
|
||||
Text text;
|
||||
text.setFont( font );
|
||||
text.setFontSize( fontSize );
|
||||
text.setString( string );
|
||||
text.hardWrapText( width );
|
||||
|
||||
const auto linesWidth = text.getLinesWidth();
|
||||
|
||||
UTEST_PRINT_STEP( "Text Shaper disabled" );
|
||||
EXPECT_VECTOREQ( linesWidth, lineWrapShaperDisabled.wrapsWidth );
|
||||
UTEST_PRINT_STEP( "Text Shaper enabled" );
|
||||
EXPECT_VECTOREQ( linesWidth, lineWrapShaperEnabled.wrapsWidth );
|
||||
UTEST_PRINT_STEP( "Text Shaper enabled w/o optimizations" );
|
||||
EXPECT_VECTOREQ( linesWidth, lineWrapShaperEnabledWOO.wrapsWidth );
|
||||
};
|
||||
|
||||
runTest( "assets/textfiles/test-hard-wrap.uext" );
|
||||
runTest( "assets/textfiles/lorem-ipsum.uext" );
|
||||
// runTest( "assets/textfiles/test-tabs.txt" );
|
||||
}
|
||||
|
||||
UTEST( FontRendering, TextHardWrap ) {
|
||||
|
||||
Reference in New Issue
Block a user