From b3748d05f2d3b08a7036cf6f8bc3d95b939ceb7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Sat, 24 Jan 2026 01:01:16 -0300 Subject: [PATCH] Add yet another text rendering test. --- .../assets/fontrendering/eepp-text-wrap.webp | Bin 0 -> 8332 bytes include/eepp/graphics/text.hpp | 2 +- src/eepp/graphics/text.cpp | 4 +- src/tests/unit_tests/fontrendering.cpp | 58 ++++++++++++++++++ 4 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 bin/unit_tests/assets/fontrendering/eepp-text-wrap.webp diff --git a/bin/unit_tests/assets/fontrendering/eepp-text-wrap.webp b/bin/unit_tests/assets/fontrendering/eepp-text-wrap.webp new file mode 100644 index 0000000000000000000000000000000000000000..2265bea2ac91e5048f8e6ecf7be27a4e07d8b536 GIT binary patch literal 8332 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⁢18mN9j;cCpud77nP=8 zUB;7=HF0eOQ81Y6_Qkar6RLO1y1Vtu#ThE)nYv9{1(Mqm5l|t@8~!aT>-)Is;y1T zDY025cd1r}(emfJY$A{npfE~A>(l~kqPa>h7nYIAPgr7fpi^*^C+oV*97BE*<>2#T z_J05^kj>X6z0r~B@;*!5St!hK={o656rS~J+$_l!jm+uF|9pB9LrYz(`%Js2(~I1h zkNU2jmnww1(fmjP2be|>TO#R5eLQA6D3>`JLGaQu(tBH6H_qcfUBJS+*_j>KKDye0 z>$o1{^S!^VDeOdU?UeS9ZzlD=L!E0Sr*2EkG_)Jk`DkH4+t%<9ck~IB4T6;+I{j@7 zqy`;1C|KmaIcPel{|a;22P)`xf+Y|SPdE3+%sv5?@)%Vj+^3oclKyeSyYt7>T7gRg z`Em!dPv}$>y$F`vwZ0H>K)e3zFut(bA+l{lf`No!KVWXHhI~C>1d=!%NzGuw^k@%f zWgt!XdUt$l=kdYU4YygP8v%b{-O26kdJ9TJAG0EBAQ{`s+mgqws@pcE=S9Yf)-py} zw?=9gGHv_y;gE$8_>g(wWM+-c@toS1YA8f38y8juoNbY~fs#M*nrC@Z>&SiU7b_0A zYfGh-ez}-siuYXv!flQ-FmKG9u9kgG?KdCYt~K3-skwi(D6o(sF69y%uDLIYktVvB z&&OqipiiD`u21e&U36-1|CsefRcTtin4R8C40Q3`>Q%?74#}w{em)7lSwEe;T$fR~ z_X`30FL{K35ygEl5^u2%j-auR?2e(aNB_zJ+HA^HS5Sj8j2IW|8 z^Vv4wyD3_pI-o`uP$zZ4|XRP0MI}3y4F?k>Iq)YdwqLZDgApQber15 zn^Zt_%X+?UoBDcPxK&;uh~d=31Neh5;3~7@_)`ggeY-9GZ{gE`7u>FyuLp161!E?p zz2tXA$&F3#_fg+p-JJtPgG5F0-=#t}@_t0gUD;o40-T70e5D^!dGF7G*Egg~fxcj{ z*y^iaq$*0zQB>eE6vk%n3B}|#*auATyiR(NKeGy8-}|}NM~y$(-bXEYu(}E0{13bU zGr?~9ppSZ~9ug1vl?Ue}Dq<1FM^45mk%O6V@XzM2b6}j+vPN&5)x1XU>qYAPTp6WK znS7PNslSiAqtrGBzjp!L^>@EtNq!JgCxnDxO2(<8#Gat1tO*gtR~aAH>?LnoufptN zoaq?k1vrEjirrCc<%mN5v;}d1u2<+Tun&GXVPEhb@I{{sd1gv`vbL&FHRG?+0gOP- zpOLDhniQnx^OkAyk0zb4r@SDxgMZs@t^aLqUn`YqQh@vGbbvTF8}|94PrFw0_Paoz zc&?$Mt*;KDqMMgIL!`~nMa3;LFvux5m7*{c(~9~L<&}SK!P3y#UqEAjuD^wfRuBpd z0kgc??)O#yx@|})02*}|iAbd+i1NpfAJ7t?VUau8Hd|02<8@Mi?+G)6yyh|=?)N#B ziahg0B@Y2W#_%rTdqUbne*e6j^3UC)*E{=Oij4v-_DFMZb+ mOutlineVertices; std::vector mOutlineColors; std::vector mLinesWidth; - TextDirection mDirection{ TextDirection::Unspecified }; void ensureGeometryUpdate(); diff --git a/src/eepp/graphics/text.cpp b/src/eepp/graphics/text.cpp index 033b5ccee..9ed8a2fcc 100644 --- a/src/eepp/graphics/text.cpp +++ b/src/eepp/graphics/text.cpp @@ -657,7 +657,7 @@ void Text::onNewString() { mCachedWidthNeedUpdate = true; mContainsColorEmoji = false; mTextHints = mString.getTextHints(); - if ( FontManager::instance()->getColorEmojiFont() != nullptr ) { + if ( mFontStyleConfig.Font && FontManager::instance()->getColorEmojiFont() != nullptr ) { if ( mFontStyleConfig.Font->getType() == FontType::TTF ) { FontTrueType* fontTrueType = static_cast( mFontStyleConfig.Font ); if ( fontTrueType->isColorEmojiFont() || !fontTrueType->isEmojiFont() ) @@ -922,7 +922,7 @@ Float Text::getTextWidth( Font* font, const Uint32& fontSize, const StringType& if ( TextShaperEnabled && font->getType() == FontType::TTF && !canSkipShaping( textDrawHints ) ) { return TextLayout::layout( string, static_cast( font ), fontSize, style, - tabWidth, outlineThickness, tabOffset, textDrawHints ) + tabWidth, outlineThickness, tabOffset, textDrawHints, direction ) ->size.getWidth(); } #endif diff --git a/src/tests/unit_tests/fontrendering.cpp b/src/tests/unit_tests/fontrendering.cpp index e11ef2feb..762a3fbfa 100644 --- a/src/tests/unit_tests/fontrendering.cpp +++ b/src/tests/unit_tests/fontrendering.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -825,3 +826,60 @@ UTEST( FontRendering, UITextTest ) { runTest(); } } + +UTEST( FontRendering, TextWrap ) { + FileSystem::changeWorkingDirectory( Sys::getProcessPath() ); + std::string loremIpsum; + FileSystem::fileGet( "assets/textfiles/lorem-ipsum.uext", loremIpsum ); + + const auto runTest = [&]() { + UIApplication app( + WindowSettings( 512, 512, "eepp - Text Wrap", WindowStyle::Default, + WindowBackend::Default, 32, {}, 1, false, true ), + UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) ); + FileSystem::changeWorkingDirectory( Sys::getProcessPath() ); + app.getWindow()->setClearColor( RGB( 255, 255, 255 ) ); + app.getWindow()->clear(); + Vector2f pos{ 5, 5 }; + Primitives p; + p.setColor( Color::Red ); + p.drawRectangle( Rectf( pos - 1.f, { 1, 501 } ) ); + p.drawRectangle( Rectf( pos - 1.f, { 501, 1 } ) ); + p.drawRectangle( Rectf( { pos.x - 1.f, 500 + pos.y }, { 502, 1 } ) ); + p.drawRectangle( Rectf( { 500 + pos.x, pos.y - 1.f }, { 1, 501 } ) ); + + Text text; + text.setFont( app.getUI()->getUIThemeManager()->getDefaultFont() ); + text.setFontSize( 16 ); + text.setColor( Color::Black ); + text.setString( loremIpsum ); + text.wrapText( 500 ); + text.draw( pos.x, pos.y ); + + text.setAlign( TEXT_ALIGN_CENTER ); + pos.y += text.getTextHeight() + 8; + text.draw( pos.x, pos.y ); + + pos.y += text.getTextHeight() + 8; + text.setAlign( TEXT_ALIGN_RIGHT ); + text.draw( pos.x, pos.y ); + + compareImages( utest_state, utest_result, app.getWindow(), "eepp-text-wrap" ); + }; + + UTEST_PRINT_STEP( "Text Shaper disabled" ); + { + BoolScopedOp op( Text::TextShaperEnabled, false ); + runTest(); + } + + UTEST_PRINT_STEP( "Text Shaper enabled" ); + { + BoolScopedOp op( Text::TextShaperEnabled, true ); + runTest(); + + UTEST_PRINT_STEP( "Text Shaper enabled w/o optimizations" ); + BoolScopedOp op2( Text::TextShaperOptimizations, false ); + runTest(); + } +}