mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-05-28 17:16:29 +03:00
1576 lines
53 KiB
C++
1576 lines
53 KiB
C++
#include "compareimages.hpp"
|
|
#include "utest.hpp"
|
|
|
|
#include <eepp/graphics/batchrenderer.hpp>
|
|
#include <eepp/graphics/fontbmfont.hpp>
|
|
#include <eepp/graphics/fontfamily.hpp>
|
|
#include <eepp/graphics/fontmanager.hpp>
|
|
#include <eepp/graphics/fontsprite.hpp>
|
|
#include <eepp/graphics/fonttruetype.hpp>
|
|
#include <eepp/graphics/globalbatchrenderer.hpp>
|
|
#include <eepp/graphics/image.hpp>
|
|
#include <eepp/graphics/primitives.hpp>
|
|
#include <eepp/graphics/renderer/renderergl.hpp>
|
|
#include <eepp/graphics/richtext.hpp>
|
|
#include <eepp/graphics/text.hpp>
|
|
#include <eepp/scene/scenemanager.hpp>
|
|
#include <eepp/system/base64.hpp>
|
|
#include <eepp/system/filesystem.hpp>
|
|
#include <eepp/system/scopedop.hpp>
|
|
#include <eepp/system/sys.hpp>
|
|
#include <eepp/ui/doc/syntaxdefinitionmanager.hpp>
|
|
#include <eepp/ui/uiapplication.hpp>
|
|
#include <eepp/ui/uicodeeditor.hpp>
|
|
#include <eepp/ui/uiscenenode.hpp>
|
|
#include <eepp/ui/uitextedit.hpp>
|
|
#include <eepp/ui/uitextview.hpp>
|
|
#include <eepp/ui/uithememanager.hpp>
|
|
#include <eepp/window/engine.hpp>
|
|
|
|
using namespace EE;
|
|
using namespace EE::Scene;
|
|
using namespace EE::System;
|
|
using namespace EE::Graphics;
|
|
using namespace EE::Window;
|
|
using namespace EE::UI;
|
|
|
|
UTEST( FontRendering, relatedFontsDisconnectReplacedCallbacks ) {
|
|
FontTrueType* font = FontTrueType::New( "RelatedFontsDisconnect-Regular" );
|
|
FontTrueType* oldBold = FontTrueType::New( "RelatedFontsDisconnect-OldBold" );
|
|
FontTrueType* newBold = FontTrueType::New( "RelatedFontsDisconnect-NewBold" );
|
|
FontTrueType* oldItalic = FontTrueType::New( "RelatedFontsDisconnect-OldItalic" );
|
|
FontTrueType* newItalic = FontTrueType::New( "RelatedFontsDisconnect-NewItalic" );
|
|
FontTrueType* oldBoldItalic = FontTrueType::New( "RelatedFontsDisconnect-OldBoldItalic" );
|
|
FontTrueType* newBoldItalic = FontTrueType::New( "RelatedFontsDisconnect-NewBoldItalic" );
|
|
|
|
font->setBoldFont( oldBold );
|
|
font->setBoldFont( newBold );
|
|
eeDelete( oldBold );
|
|
EXPECT_EQ( newBold, font->getBoldFont() );
|
|
|
|
font->setItalicFont( oldItalic );
|
|
font->setItalicFont( newItalic );
|
|
eeDelete( oldItalic );
|
|
EXPECT_EQ( newItalic, font->getItalicFont() );
|
|
|
|
font->setBoldItalicFont( oldBoldItalic );
|
|
font->setBoldItalicFont( newBoldItalic );
|
|
eeDelete( oldBoldItalic );
|
|
EXPECT_EQ( newBoldItalic, font->getBoldItalicFont() );
|
|
|
|
eeDelete( font );
|
|
eeDelete( newBold );
|
|
eeDelete( newItalic );
|
|
eeDelete( newBoldItalic );
|
|
}
|
|
|
|
UTEST( FontRendering, fontsTest ) {
|
|
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
|
|
|
auto win = Engine::instance()->createWindow(
|
|
WindowSettings( 1024, 650, "eepp - Fonts", WindowStyle::Default, WindowBackend::Default, 32,
|
|
{}, 1, false, true ) );
|
|
|
|
ASSERT_TRUE_MSG( win->isOpen(), "Failed to create Window" );
|
|
|
|
UTEST_PRINT_INFO( GLi->getRenderer().c_str() );
|
|
|
|
win->setClearColor( RGB( 230, 230, 230 ) );
|
|
|
|
String Txt( "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod "
|
|
"tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, "
|
|
"quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo "
|
|
"consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse "
|
|
"cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non "
|
|
"proident, sunt in culpa qui officia deserunt mollit anim id est laborum." );
|
|
|
|
FontTrueType* fontTest = FontTrueType::New( "DejaVuSansMono" );
|
|
fontTest->loadFromFile( "../assets/fonts/DejaVuSansMono.ttf" );
|
|
|
|
FontTrueType* fontTest2 = FontTrueType::New( "NotoSans-Regular" );
|
|
fontTest2->loadFromFile( "../assets/fonts/NotoSans-Regular.ttf" );
|
|
|
|
FontTrueType* fontEmoji = FontTrueType::New( "NotoEmoji-Regular" );
|
|
fontEmoji->loadFromFile( "../assets/fonts/NotoEmoji-Regular.ttf" );
|
|
|
|
FontTrueType* fontEmojiColor = FontTrueType::New( "NotoColorEmoji" );
|
|
fontEmojiColor->loadFromFile( "../assets/fonts/NotoColorEmoji.ttf" );
|
|
|
|
FontBMFont* fontBMFont = FontBMFont::New( "bmfont" );
|
|
fontBMFont->loadFromFile( "../assets/fonts/bmfont.fnt" );
|
|
|
|
FontSprite* fontSprite = FontSprite::New( "alagard" );
|
|
fontSprite->loadFromFile( "../assets/fonts/custom_alagard.png", Color::Fuchsia, 32, -4 );
|
|
|
|
Text text;
|
|
text.setFont( fontTest );
|
|
text.setFontSize( 24 );
|
|
text.setAlign( TEXT_ALIGN_CENTER );
|
|
text.setString( Txt );
|
|
text.hardWrapText( win->getWidth() - 96 );
|
|
|
|
int size = (int)text.getString().size();
|
|
|
|
for ( int i = 0; i < size; i++ ) {
|
|
text.setFillColor( Color( 255 * i / size, 0, 0, 255 ), i, i + 1 );
|
|
}
|
|
|
|
Text text2;
|
|
text2.setFont( fontTest2 );
|
|
text2.setString( "Lorem ipsum dolor sit amet, consectetur adipisicing elit. 👽" );
|
|
text2.setFontSize( 32 );
|
|
text2.setFillColor( Color::Black );
|
|
|
|
Text text3;
|
|
text3.setFont( fontTest );
|
|
text3.setString( text2.getString() );
|
|
text3.setFontSize( 24 );
|
|
text3.setFillColor( Color( 255, 255, 255, 255 ) );
|
|
text3.setOutlineThickness( 2 );
|
|
text3.setOutlineColor( Color( 0, 0, 0, 255 ) );
|
|
|
|
Text text4;
|
|
text4.setFont( fontBMFont );
|
|
text4.setString( text2.getString() );
|
|
text4.setFontSize( 45 );
|
|
text4.setFillColor( Color::Black );
|
|
|
|
Text text5;
|
|
text5.setFont( fontSprite );
|
|
text5.setString( text2.getString() );
|
|
text5.setFontSize( 38 );
|
|
|
|
Text text6;
|
|
text6.setFont( fontEmojiColor );
|
|
text6.setFontSize( 64 );
|
|
text6.setString( "👽 😀 💩 😃 👻" );
|
|
|
|
Text text7;
|
|
text7.setFont( fontEmoji );
|
|
text7.setFontSize( 32 );
|
|
text7.setString( "👽 😀 💩 😃 👻" );
|
|
text7.setFillColor( Color::Gray );
|
|
text7.setOutlineThickness( 2 );
|
|
text7.setOutlineColor( Color( 0, 0, 0, 255 ) );
|
|
|
|
{
|
|
const auto runTest = [&]() {
|
|
win->clear();
|
|
|
|
Float offsetY = 0;
|
|
text.draw( 0, 0 );
|
|
text2.draw( 0, ( offsetY += text.getTextHeight() + 16 ) );
|
|
text7.draw( 0, ( offsetY += text2.getTextHeight() + 16 ) );
|
|
text3.draw( 0, ( offsetY += text7.getTextHeight() + 16 ) );
|
|
text4.draw( 0, ( offsetY += text3.getTextHeight() + 16 ) );
|
|
text5.draw( 0, ( offsetY += text4.getTextHeight() + 16 ) );
|
|
text6.draw( 0, ( offsetY += text5.getTextHeight() + 16 ) );
|
|
|
|
compareImages( utest_state, utest_result, win, "eepp-fonts" );
|
|
};
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
Engine::destroySingleton();
|
|
}
|
|
|
|
UTEST( FontRendering, loadFontFaceDataURI ) {
|
|
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
|
|
|
auto win = Engine::instance()->createWindow(
|
|
WindowSettings( 640, 480, "eepp - Font Data URI", WindowStyle::Default,
|
|
WindowBackend::Default, 32, {}, 1, false, true ) );
|
|
|
|
ASSERT_TRUE_MSG( win->isOpen(), "Failed to create Window" );
|
|
|
|
UI::UISceneNode* sceneNode = UI::UISceneNode::New();
|
|
SceneManager::instance()->add( sceneNode );
|
|
UI::UIThemeManager* themeManager = sceneNode->getUIThemeManager();
|
|
|
|
FontTrueType* baseFont = FontTrueType::New( "NotoSans-Regular" );
|
|
baseFont->loadFromFile( "../assets/fonts/NotoSans-Regular.ttf" );
|
|
themeManager->setDefaultFont( baseFont );
|
|
|
|
std::string fontData;
|
|
bool readOk = FileSystem::fileGet( "../assets/fonts/DejaVuSansMono.ttf", fontData );
|
|
ASSERT_TRUE_MSG( readOk, "Failed to read font file" );
|
|
ASSERT_TRUE_MSG( !fontData.empty(), "Font data is empty" );
|
|
|
|
std::string base64Font;
|
|
Base64::encode( std::string_view( fontData ), base64Font );
|
|
ASSERT_TRUE_MSG( !base64Font.empty(), "Base64 encoding failed" );
|
|
|
|
std::string css = "@font-face {\n"
|
|
" font-family: 'DataURIFont';\n"
|
|
" src: url('data:font/ttf;charset=utf-8;base64," +
|
|
base64Font +
|
|
"') format('truetype');\n"
|
|
" font-weight: normal;\n"
|
|
" font-style: normal;\n"
|
|
"}";
|
|
|
|
sceneNode->combineStyleSheet( css, false, String::hash( css ), URI() );
|
|
|
|
Font* loadedFont = FontManager::instance()->getByName( "DataURIFont" );
|
|
ASSERT_NE( loadedFont, nullptr );
|
|
ASSERT_TRUE_MSG( loadedFont->loaded(), "Font loaded via data URI is not loaded" );
|
|
|
|
Engine::destroySingleton();
|
|
}
|
|
|
|
UTEST( FontRendering, editorTest ) {
|
|
const auto runTest = [&]() {
|
|
UIApplication app(
|
|
WindowSettings( 1024, 650, "eepp - CodeEditor", WindowStyle::Default,
|
|
WindowBackend::Default, 32, {}, 1, false, true ),
|
|
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) );
|
|
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
|
auto* editor = UICodeEditor::New();
|
|
editor->setPixelsSize( app.getUI()->getPixelsSize() );
|
|
editor->loadFromFile( "assets/textformat/english.utf8.lf.bom.txt" );
|
|
SceneManager::instance()->update();
|
|
SceneManager::instance()->draw();
|
|
compareImages( utest_state, utest_result, app.getWindow(), "eepp-editor-monospace" );
|
|
};
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
UTEST( FontRendering, textEditTest ) {
|
|
const auto runTest = [&]() {
|
|
UIApplication app(
|
|
WindowSettings( 1024, 650, "eepp - TextEdit", WindowStyle::Default,
|
|
WindowBackend::Default, 32, {}, 1, false, true ),
|
|
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) );
|
|
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
|
auto* editor = UITextEdit::New();
|
|
editor->setPixelsSize( app.getUI()->getPixelsSize() );
|
|
editor->loadFromFile( "assets/textformat/english.utf8.lf.bom.txt" );
|
|
SceneManager::instance()->update();
|
|
SceneManager::instance()->draw();
|
|
compareImages( utest_state, utest_result, app.getWindow(), "eepp-textedit" );
|
|
};
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
UTEST( FontRendering, tabsTest ) {
|
|
const auto runTest = [&]() {
|
|
UIApplication app(
|
|
WindowSettings( 1024, 650, "eepp - Tabs Test", WindowStyle::Default,
|
|
WindowBackend::Default, 32, {}, 1, false, true ),
|
|
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) );
|
|
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
|
auto* editor = UICodeEditor::New();
|
|
editor->setPixelsSize( app.getUI()->getPixelsSize() );
|
|
editor->loadFromFile( "assets/textfiles/test-tabs.txt" );
|
|
SceneManager::instance()->update();
|
|
SceneManager::instance()->draw();
|
|
compareImages( utest_state, utest_result, app.getWindow(),
|
|
"eepp-editor-monospace-tabs-test" );
|
|
};
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
UTEST( FontRendering, tabStopTest ) {
|
|
const auto runTest = [&]() {
|
|
UIApplication app(
|
|
WindowSettings( 1024, 650, "eepp - Tab Stop Test", WindowStyle::Default,
|
|
WindowBackend::Default, 32, {}, 1, false, true ),
|
|
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) );
|
|
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
|
auto* editor = UICodeEditor::New();
|
|
editor->setTabStops( true );
|
|
editor->setPixelsSize( app.getUI()->getPixelsSize() );
|
|
editor->loadFromFile( "assets/textfiles/test-tabs.txt" );
|
|
SceneManager::instance()->update();
|
|
SceneManager::instance()->draw();
|
|
compareImages( utest_state, utest_result, app.getWindow(),
|
|
"eepp-editor-monospace-tab-stop-test" );
|
|
};
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
UTEST( FontRendering, tabsTextEditTest ) {
|
|
const auto runTest = [&]() {
|
|
UIApplication app(
|
|
WindowSettings( 1024, 650, "eepp - TextEdit - Tabs Test", WindowStyle::Default,
|
|
WindowBackend::Default, 32, {}, 1, false, true ),
|
|
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) );
|
|
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
|
auto* editor = UITextEdit::New();
|
|
editor->setPixelsSize( app.getUI()->getPixelsSize() );
|
|
editor->loadFromFile( "assets/textfiles/test-tabs.txt" );
|
|
SceneManager::instance()->update();
|
|
SceneManager::instance()->draw();
|
|
compareImages( utest_state, utest_result, app.getWindow(), "eepp-text-edit-tabs-test" );
|
|
};
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
UTEST( FontRendering, tabStopTextEditTest ) {
|
|
const auto runTest = [&]() {
|
|
UIApplication app(
|
|
WindowSettings( 1024, 650, "eepp - TextEdit - Tab Stop Test", WindowStyle::Default,
|
|
WindowBackend::Default, 32, {}, 1, false, true ),
|
|
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) );
|
|
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
|
auto* editor = UITextEdit::New();
|
|
editor->setTabStops( true );
|
|
editor->setPixelsSize( app.getUI()->getPixelsSize() );
|
|
editor->loadFromFile( "assets/textfiles/test-tabs.txt" );
|
|
SceneManager::instance()->update();
|
|
SceneManager::instance()->draw();
|
|
compareImages( utest_state, utest_result, app.getWindow(), "eepp-text-edit-tab-stop-test" );
|
|
};
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
UTEST( FontRendering, textViewTest ) {
|
|
const auto runTest = [&]() {
|
|
UIApplication app( WindowSettings( 1024, 650, "eepp - TextView", WindowStyle::Default,
|
|
WindowBackend::Default, 32, {}, 1, false, true ),
|
|
UIApplication::Settings(
|
|
Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1.5f ) );
|
|
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
|
auto* view = UITextView::New();
|
|
view->setPixelsSize( app.getUI()->getPixelsSize() );
|
|
std::string file;
|
|
FileSystem::fileGet( "assets/textformat/english.utf8.lf.bom.txt", file );
|
|
view->setText( file );
|
|
SceneManager::instance()->update();
|
|
SceneManager::instance()->draw();
|
|
compareImages( utest_state, utest_result, app.getWindow(), "eepp-textview" );
|
|
};
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
UTEST( FontRendering, textEditBengaliTest ) {
|
|
BoolScopedOp op( Text::TextShaperEnabled, true );
|
|
UIApplication app(
|
|
WindowSettings( 1024, 650, "eepp - TextEdit Bengali", WindowStyle::Default,
|
|
WindowBackend::Default, 32, {}, 1, false, true ),
|
|
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1.5f ) );
|
|
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
|
FontTrueType* bengaliFont =
|
|
FontTrueType::New( "NotoSansBengali-Regular", "assets/fonts/NotoSansBengali-Regular.ttf" );
|
|
FontManager::instance()->addFallbackFont( bengaliFont );
|
|
UTEST_PRINT_STEP( "Text Shaper enabled" );
|
|
auto* editor = UITextEdit::New();
|
|
// editor->setFontSize( PixelDensity::dpToPx( 12 ) );
|
|
editor->setPixelsSize( app.getUI()->getPixelsSize() );
|
|
editor->loadFromFile( "assets/textfiles/test-bengali.uext" );
|
|
SceneManager::instance()->update();
|
|
SceneManager::instance()->draw();
|
|
compareImages( utest_state, utest_result, app.getWindow(), "eepp-textedit-bengali" );
|
|
}
|
|
|
|
UTEST( FontRendering, textEditArabicTest ) {
|
|
BoolScopedOp op( Text::TextShaperEnabled, true );
|
|
UIApplication app(
|
|
WindowSettings( 1024, 650, "eepp - TextEdit Arabic", WindowStyle::Default,
|
|
WindowBackend::Default, 32, {}, 1, false, true ),
|
|
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1.5f ) );
|
|
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
|
FontTrueType* arabicFont =
|
|
FontTrueType::New( "NotoNaskhArabic-Regular", "assets/fonts/NotoNaskhArabic-Regular.ttf" );
|
|
FontManager::instance()->addFallbackFont( arabicFont );
|
|
UTEST_PRINT_STEP( "Text Shaper enabled" );
|
|
auto* editor = UITextEdit::New();
|
|
// editor->setFontSize( PixelDensity::dpToPx( 12 ) );
|
|
editor->setPixelsSize( app.getUI()->getPixelsSize() );
|
|
editor->loadFromFile( "assets/textfiles/test-arabic.uext" );
|
|
SceneManager::instance()->update();
|
|
SceneManager::instance()->draw();
|
|
compareImages( utest_state, utest_result, app.getWindow(), "eepp-textedit-arabic" );
|
|
}
|
|
|
|
UTEST( FontRendering, textEditHebrewTest ) {
|
|
BoolScopedOp op( Text::TextShaperEnabled, true );
|
|
UIApplication app(
|
|
WindowSettings( 1024, 650, "eepp - TextEdit Hebrew", WindowStyle::Default,
|
|
WindowBackend::Default, 32, {}, 1, false, true ),
|
|
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1.5f ) );
|
|
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
|
FontTrueType* hebrewFont =
|
|
FontTrueType::New( "NotoSansHebrew-Regular", "assets/fonts/NotoSansHebrew-Regular.ttf" );
|
|
FontManager::instance()->addFallbackFont( hebrewFont );
|
|
UTEST_PRINT_STEP( "Text Shaper enabled" );
|
|
auto* editor = UITextEdit::New();
|
|
// editor->setFontSize( PixelDensity::dpToPx( 12 ) );
|
|
editor->setPixelsSize( app.getUI()->getPixelsSize() );
|
|
editor->loadFromFile( "assets/textfiles/test-hebrew.uext" );
|
|
SceneManager::instance()->update();
|
|
SceneManager::instance()->draw();
|
|
compareImages( utest_state, utest_result, app.getWindow(), "eepp-textedit-hebrew" );
|
|
}
|
|
|
|
UTEST( FontRendering, textSizes ) {
|
|
auto win = Engine::instance()->createWindow(
|
|
WindowSettings( 1024, 650, "eepp - Text Sizes", WindowStyle::Default,
|
|
WindowBackend::Default, 32, {}, 1, false, true ) );
|
|
|
|
ASSERT_TRUE_MSG( win->isOpen(), "Failed to create Window" );
|
|
|
|
Text::TextShaperEnabled = false;
|
|
|
|
FontTrueType* font = FontTrueType::New( "NotoSans-Regular" );
|
|
font->loadFromFile( "../assets/fonts/NotoSans-Regular.ttf" );
|
|
|
|
FontStyleConfig config;
|
|
config.Font = font;
|
|
config.CharacterSize = 12;
|
|
config.Style = 0;
|
|
|
|
String txt( "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n"
|
|
"tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\n"
|
|
"quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\n"
|
|
"consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\n"
|
|
"cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\n"
|
|
"proident, sunt in culpa qui officia deserunt mollit anim id est laborum." );
|
|
|
|
const auto runTest = [&]() {
|
|
Sizef size = Text::draw( txt, Vector2f::Zero, config );
|
|
EXPECT_EQ( 445, size.getWidth() );
|
|
EXPECT_EQ( 96, size.getHeight() );
|
|
EXPECT_EQ( 445, Text::getTextWidth( txt, config ) );
|
|
|
|
Vector2i topPos{ 120, 0 };
|
|
EXPECT_EQ( 19, Text::findCharacterFromPos( topPos, true, config.Font, config.CharacterSize,
|
|
txt, 0 ) );
|
|
EXPECT_EQ( 19, Text::findCharacterFromPos( topPos, false, config.Font, config.CharacterSize,
|
|
txt, 0 ) );
|
|
|
|
Vector2i startPos{ 120, 7 };
|
|
EXPECT_EQ( 19, Text::findCharacterFromPos( startPos, true, config.Font,
|
|
config.CharacterSize, txt, 0 ) );
|
|
EXPECT_EQ( 19, Text::findCharacterFromPos( startPos, false, config.Font,
|
|
config.CharacterSize, txt, 0 ) );
|
|
|
|
Vector2i middlePos{ 120, 64 };
|
|
EXPECT_EQ( 242, Text::findCharacterFromPos( middlePos, true, config.Font,
|
|
config.CharacterSize, txt, 0 ) );
|
|
EXPECT_EQ( 242, Text::findCharacterFromPos( middlePos, false, config.Font,
|
|
config.CharacterSize, txt, 0 ) );
|
|
|
|
Vector2i endPos{ 120, 103 };
|
|
EXPECT_EQ( 395, Text::findCharacterFromPos( endPos, true, config.Font, config.CharacterSize,
|
|
txt, 0 ) );
|
|
EXPECT_EQ( -1, Text::findCharacterFromPos( endPos, false, config.Font, config.CharacterSize,
|
|
txt, 0 ) );
|
|
|
|
EXPECT_EQ( 18ul, Text::findLastCharPosWithinLength( txt, 120, config ) );
|
|
EXPECT_EQ( 446ul, Text::findLastCharPosWithinLength( txt, 1000, config ) );
|
|
|
|
Vector2f pos = Text::findCharacterPos( 19, config.Font, config.CharacterSize, txt, 0 );
|
|
EXPECT_EQ( 120, pos.x );
|
|
EXPECT_EQ( 0, pos.y );
|
|
|
|
Text text;
|
|
text.setStyleConfig( config );
|
|
text.setString( txt );
|
|
EXPECT_EQ( 445, text.getTextWidth() );
|
|
EXPECT_EQ( 96, text.getTextHeight() );
|
|
EXPECT_EQ( 446, text.getLocalBounds().getWidth() );
|
|
EXPECT_EQ( 93, text.getLocalBounds().getHeight() );
|
|
EXPECT_EQ( 19, text.findCharacterFromPos( startPos, true ) );
|
|
EXPECT_EQ( 19, text.findCharacterFromPos( startPos, false ) );
|
|
EXPECT_EQ( 242, text.findCharacterFromPos( middlePos, true ) );
|
|
EXPECT_EQ( 242, text.findCharacterFromPos( middlePos, false ) );
|
|
EXPECT_EQ( 395, text.findCharacterFromPos( endPos ) );
|
|
EXPECT_EQ( -1, text.findCharacterFromPos( endPos, false ) );
|
|
pos = text.findCharacterPos( 19 );
|
|
EXPECT_EQ( 120, pos.x );
|
|
EXPECT_EQ( 0, pos.y );
|
|
};
|
|
|
|
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 op( Text::TextShaperEnabled, true );
|
|
BoolScopedOp op2( Text::TextShaperOptimizations, false );
|
|
runTest();
|
|
}
|
|
|
|
Engine::destroySingleton();
|
|
}
|
|
|
|
UTEST( FontRendering, textStyles ) {
|
|
auto win = Engine::instance()->createWindow(
|
|
WindowSettings( 1024, 230, "eepp - Text Styles", WindowStyle::Default,
|
|
WindowBackend::Default, 32, {}, 1, false, true ) );
|
|
|
|
ASSERT_TRUE_MSG( win->isOpen(), "Failed to create Window" );
|
|
|
|
Text::TextShaperEnabled = false;
|
|
|
|
FontTrueType* font = FontTrueType::New( "NotoSans-Regular" );
|
|
font->loadFromFile( "../assets/fonts/NotoSans-Regular.ttf" );
|
|
FontFamily::loadFromRegular( font );
|
|
|
|
win->setClearColor( RGB( 255, 255, 255 ) );
|
|
|
|
FontStyleConfig config;
|
|
config.Font = font;
|
|
config.FontColor = Color::Black;
|
|
config.CharacterSize = 20;
|
|
config.OutlineColor = Color::Black;
|
|
config.ShadowColor = Color::lightgray;
|
|
|
|
String txt( "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n"
|
|
"tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\n"
|
|
"quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\n"
|
|
"consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\n"
|
|
"cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\n"
|
|
"proident, sunt in culpa qui officia deserunt mollit anim id est laborum." );
|
|
|
|
const auto runTest = [&]( std::string_view styleName, Uint32 textAlign ) {
|
|
win->clear();
|
|
Text text;
|
|
text.setStyleConfig( config );
|
|
text.setString( txt );
|
|
text.setAlign( textAlign );
|
|
text.draw( 32, 32 );
|
|
compareImages( utest_state, utest_result, win, "eepp-text-style-" + styleName );
|
|
};
|
|
|
|
const auto runTestSuite = [&]( Uint32 style, std::string_view styleName,
|
|
Uint32 textAlign = TEXT_ALIGN_LEFT ) {
|
|
config.Style = style;
|
|
|
|
UTEST_PRINT_STEP( styleName.data() );
|
|
|
|
{
|
|
UTEST_PRINT_STEP( " Text Shaper disabled" );
|
|
BoolScopedOp op( Text::TextShaperEnabled, false );
|
|
runTest( styleName, textAlign );
|
|
}
|
|
|
|
{
|
|
UTEST_PRINT_STEP( " Text Shaper enabled" );
|
|
BoolScopedOp op( Text::TextShaperEnabled, true );
|
|
runTest( styleName, textAlign );
|
|
|
|
UTEST_PRINT_STEP( " Text Shaper enabled w/o optimizations" );
|
|
BoolScopedOp op2( Text::TextShaperOptimizations, false );
|
|
runTest( styleName, textAlign );
|
|
}
|
|
};
|
|
|
|
runTestSuite( Text::Regular, "regular" );
|
|
runTestSuite( Text::Bold, "bold" );
|
|
runTestSuite( Text::Italic, "italic" );
|
|
runTestSuite( Text::Underlined, "underline" );
|
|
runTestSuite( Text::StrikeThrough, "strikethrough" );
|
|
runTestSuite( Text::Shadow, "shadow" );
|
|
config.FontColor = Color::White;
|
|
config.OutlineThickness = 1;
|
|
runTestSuite( Text::Regular, "outline" );
|
|
config.FontColor = Color::Black;
|
|
config.OutlineThickness = 0;
|
|
runTestSuite( Text::Regular, "regular-center", TEXT_ALIGN_CENTER );
|
|
runTestSuite( Text::Regular, "regular-right", TEXT_ALIGN_RIGHT );
|
|
runTestSuite( Text::Underlined, "underline-center", TEXT_ALIGN_CENTER );
|
|
runTestSuite( Text::Underlined, "underline-right", TEXT_ALIGN_RIGHT );
|
|
runTestSuite( Text::StrikeThrough, "strikethrough-center", TEXT_ALIGN_CENTER );
|
|
runTestSuite( Text::StrikeThrough, "strikethrough-right", TEXT_ALIGN_RIGHT );
|
|
|
|
Engine::destroySingleton();
|
|
}
|
|
|
|
UTEST( FontRendering, emojisWithText ) {
|
|
auto win = Engine::instance()->createWindow(
|
|
WindowSettings( 1024, 230, "eepp - Emojis With Text", WindowStyle::Default,
|
|
WindowBackend::Default, 32, {}, 1, false, true ) );
|
|
|
|
ASSERT_TRUE_MSG( win->isOpen(), "Failed to create Window" );
|
|
|
|
Text::TextShaperEnabled = false;
|
|
|
|
FontTrueType* font = FontTrueType::New( "NotoSans-Regular" );
|
|
font->loadFromFile( "../assets/fonts/NotoSans-Regular.ttf" );
|
|
FontFamily::loadFromRegular( font );
|
|
|
|
FontTrueType* fontEmojiColor = FontTrueType::New( "NotoColorEmoji" );
|
|
fontEmojiColor->loadFromFile( "../assets/fonts/NotoColorEmoji.ttf" );
|
|
|
|
win->setClearColor( RGB( 255, 255, 255 ) );
|
|
|
|
FontStyleConfig config;
|
|
config.Font = font;
|
|
config.FontColor = Color::Black;
|
|
config.CharacterSize = 16;
|
|
|
|
String txt(
|
|
R"txt(👻 Lorem ipsum dolor sit amet, 👻 consectetur adipisicing elit, sed do eiusmod🤯 tempor incididunt ut labore et dolore magna
|
|
aliqua. Ut enim ad😎 minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat 🤖.
|
|
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur 🧐. Excepteur sint occaecat
|
|
cupidatat non proident👽, sunt in culpa qui officia deserunt mollit anim id est laborum. 😀)txt" );
|
|
|
|
const auto runTest = [&]() {
|
|
win->clear();
|
|
Text text;
|
|
text.setStyleConfig( config );
|
|
text.setString( txt );
|
|
text.draw( 32, 32 );
|
|
compareImages( utest_state, utest_result, win, "eepp-emojis-with-text" );
|
|
};
|
|
|
|
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();
|
|
|
|
Engine::destroySingleton();
|
|
}
|
|
|
|
UTEST( FontRendering, textSetFillColor ) {
|
|
auto win = Engine::instance()->createWindow(
|
|
WindowSettings( 1024, 230, "eepp - Text Set Fill Color", WindowStyle::Default,
|
|
WindowBackend::Default, 32, {}, 1, false, true ) );
|
|
|
|
ASSERT_TRUE_MSG( win->isOpen(), "Failed to create Window" );
|
|
|
|
UTEST_PRINT_INFO( GLi->getRenderer().c_str() );
|
|
|
|
win->setClearColor( RGB( 230, 230, 230 ) );
|
|
|
|
FontTrueType* arabicFont =
|
|
FontTrueType::New( "NotoNaskhArabic-Regular", "assets/fonts/NotoNaskhArabic-Regular.ttf" );
|
|
|
|
Text text;
|
|
text.setFont( arabicFont );
|
|
text.setFontSize( 64 );
|
|
text.setAlign( TEXT_ALIGN_CENTER );
|
|
std::string arabicTxtUtf8;
|
|
FileSystem::fileGet( "assets/textfiles/test-arabic-simple.uext", arabicTxtUtf8 );
|
|
String arabicTxt( arabicTxtUtf8 );
|
|
text.setString( arabicTxt );
|
|
text.setFillColor( Color::Black );
|
|
|
|
const auto runTest = [&]( std::string_view testName ) {
|
|
win->clear();
|
|
text.draw( 0, win->getHeight() * 0.5f - text.getTextHeight() * 0.5f );
|
|
compareImages( utest_state, utest_result, win,
|
|
std::string( "eepp-text-set-fill-color-" ) + std::string( testName ) );
|
|
};
|
|
|
|
UTEST_PRINT_STEP( "Text Shaper enabled" );
|
|
{
|
|
BoolScopedOp op( Text::TextShaperEnabled, true );
|
|
|
|
// Test Vector Fill
|
|
{
|
|
std::vector<Color> colors;
|
|
for ( size_t i = 0; i < arabicTxt.size(); i++ ) {
|
|
// Alternating colors
|
|
if ( i % 3 == 0 )
|
|
colors.push_back( Color::Red );
|
|
else if ( i % 3 == 1 )
|
|
colors.push_back( Color::Green );
|
|
else
|
|
colors.push_back( Color::Blue );
|
|
}
|
|
text.setFillColor( colors );
|
|
runTest( "vector" );
|
|
}
|
|
|
|
// Test Range Fill
|
|
{
|
|
text.setFillColor( Color::Black );
|
|
// Color "World" (بالعالم) in Red. It's at the end of the string.
|
|
// "مرحباً" (Hello) is 6 chars + space = 7.
|
|
// "بالعالم" (World) starts at index 7.
|
|
if ( arabicTxt.size() > 7 ) {
|
|
text.setFillColor( Color::Red, 7, arabicTxt.size() );
|
|
}
|
|
runTest( "range" );
|
|
}
|
|
}
|
|
|
|
Engine::destroySingleton();
|
|
}
|
|
|
|
UTEST( FontRendering, UITextTest ) {
|
|
const auto runTest = [&]() {
|
|
UIApplication app(
|
|
WindowSettings( 1024, 650, "eepp - UI Text Test", WindowStyle::Default,
|
|
WindowBackend::Default, 32, {}, 1, false, true ),
|
|
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) );
|
|
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
|
app.getUI()->loadLayoutFromFile( "assets/layouts/ui_text_test.xml" );
|
|
SceneManager::instance()->update();
|
|
SceneManager::instance()->draw();
|
|
compareImages( utest_state, utest_result, app.getWindow(), "eepp-ui-text-test" );
|
|
};
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
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, 555, "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, 546 } ) );
|
|
p.drawRectangle( Rectf( pos - 1.f, { 501, 1 } ) );
|
|
p.drawRectangle( Rectf( { pos.x - 1.f, 544 + pos.y }, { 502, 1 } ) );
|
|
p.drawRectangle( Rectf( { 500 + pos.x, pos.y - 1.f }, { 1, 546 } ) );
|
|
|
|
Text text;
|
|
text.setFont( app.getUI()->getUIThemeManager()->getDefaultFont() );
|
|
text.setFontSize( 16 );
|
|
text.setColor( Color::Black );
|
|
text.setString( loremIpsum );
|
|
text.setLineWrapMode( LineWrapMode::Word );
|
|
text.setMaxWrapWidth( 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();
|
|
}
|
|
}
|
|
|
|
UTEST( FontRendering, TextLayoutWrap ) {
|
|
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
|
std::string loremIpsum;
|
|
FileSystem::fileGet( "assets/textfiles/lorem-ipsum.uext", loremIpsum );
|
|
|
|
const auto runTest = [&]() {
|
|
UIApplication app(
|
|
WindowSettings( 512, 555, "eepp - Text Layout Wrap", WindowStyle::Default,
|
|
WindowBackend::Default, 32, {}, 1, false, true ),
|
|
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) );
|
|
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
|
|
|
BatchRenderer* BR = GlobalBatchRenderer::instance();
|
|
auto drawGlyph = [BR]( GlyphDrawable* gd, const Vector2f& position, const Color& color ) {
|
|
BR->quadsSetColor( color );
|
|
BR->quadsSetTexCoord( gd->getSrcRect().Left, gd->getSrcRect().Top,
|
|
gd->getSrcRect().Left + gd->getSrcRect().Right,
|
|
gd->getSrcRect().Top + gd->getSrcRect().Bottom );
|
|
BR->batchQuad( position.x + gd->getGlyphOffset().x, position.y + gd->getGlyphOffset().y,
|
|
gd->getDestSize().getWidth(), gd->getDestSize().getHeight() );
|
|
};
|
|
|
|
app.getWindow()->setClearColor( RGB( 255, 255, 255 ) );
|
|
app.getWindow()->clear();
|
|
|
|
Vector2f pos{ 5, 5 };
|
|
Primitives p;
|
|
p.setColor( Color::Red );
|
|
p.drawPixelPerfectLineRectangle( { { 4, 4 }, { 502, 546 } } );
|
|
|
|
FontTrueType* font =
|
|
static_cast<FontTrueType*>( app.getUI()->getUIThemeManager()->getDefaultFont() );
|
|
auto fontSize = 16;
|
|
Texture* fontTexture = font->getTexture( fontSize );
|
|
BR->setBlendMode( BlendMode::Alpha() );
|
|
BR->quadsBegin();
|
|
BR->setTexture( fontTexture, fontTexture->getCoordinateType() );
|
|
|
|
String string( loremIpsum );
|
|
|
|
// Remove the emoji since it won't work in this context
|
|
if ( Font::isEmojiCodePoint( string[string.size() - 1] ) )
|
|
string.pop_back();
|
|
|
|
auto layout = TextLayout::layout( string, font, fontSize, 0, 4, 0, {}, 0,
|
|
TextDirection::LeftToRight, LineWrapMode::Word, 500 );
|
|
|
|
for ( const auto& sp : layout->paragraphs ) {
|
|
for ( const auto& sg : sp.shapedGlyphs ) {
|
|
auto* gd = sg.font->getGlyphDrawableFromGlyphIndex( sg.glyphIndex, fontSize );
|
|
if ( gd )
|
|
drawGlyph( gd, pos + sg.position, Color::Black );
|
|
}
|
|
}
|
|
|
|
BR->draw();
|
|
|
|
compareImages( utest_state, utest_result, app.getWindow(), "eepp-text-layout-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();
|
|
}
|
|
}
|
|
|
|
UTEST( FontRendering, LineWrapInfo ) {
|
|
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
|
|
|
UIApplication app(
|
|
WindowSettings( 1024, 650, "eepp - LineWrapInfo Test", WindowStyle::Default,
|
|
WindowBackend::Default, 32, {}, 1, false, true ),
|
|
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) );
|
|
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
|
|
|
Font* font = app.getUI()->getUIThemeManager()->getDefaultFont();
|
|
Float width = app.getWindow()->getSize().getWidth();
|
|
int fontSize = 16;
|
|
LineWrapMode mode = LineWrapMode::Word;
|
|
|
|
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" );
|
|
|
|
std::string string;
|
|
FileSystem::fileGet( path, string );
|
|
LineWrapInfoEx lineWrapShaperDisabled;
|
|
LineWrapInfoEx lineWrapShaperEnabled;
|
|
LineWrapInfoEx lineWrapShaperEnabledWOO;
|
|
|
|
{
|
|
UTEST_PRINT_STEP( "Text Shaper disabled" );
|
|
BoolScopedOp op( Text::TextShaperEnabled, false );
|
|
String str( string );
|
|
lineWrapShaperDisabled =
|
|
LineWrap::computeLineBreaksEx( string, font, fontSize, width, mode );
|
|
}
|
|
|
|
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" );
|
|
runTest( "assets/textfiles/quota.uext" );
|
|
}
|
|
|
|
UTEST( FontRendering, TextHardWrap ) {
|
|
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
|
std::string string;
|
|
FileSystem::fileGet( "assets/textfiles/test-hard-wrap.uext", string );
|
|
|
|
const auto runTest = [&]() {
|
|
UIApplication app(
|
|
WindowSettings( 1024, 650, "eepp - Text Hard Wrap", WindowStyle::Default,
|
|
WindowBackend::Default, 32, {}, 1, false, true ),
|
|
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) );
|
|
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
|
|
|
auto colors = SyntaxColorScheme::getDefaultDark();
|
|
auto syntax = SyntaxDefinitionManager::instance()->getByLanguageName( "Markdown" );
|
|
|
|
app.getWindow()->setClearColor( colors.getEditorColor( "background"_sst ).toRGB() );
|
|
app.getWindow()->clear();
|
|
|
|
Text text;
|
|
text.setFont( app.getUI()->getUIThemeManager()->getDefaultFont() );
|
|
text.setFontSize( 16 );
|
|
text.setColor( Color::Black );
|
|
text.setString( string );
|
|
text.hardWrapText( app.getWindow()->getSize().getWidth() );
|
|
SyntaxTokenizer::tokenizeText( syntax, colors, &text );
|
|
text.draw( 0, 0 );
|
|
|
|
compareImages( utest_state, utest_result, app.getWindow(), "eepp-text-hard-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();
|
|
}
|
|
}
|
|
|
|
UTEST( FontRendering, UITextViewWrappedSelection ) {
|
|
const auto runTest = [&]() {
|
|
UIApplication app(
|
|
WindowSettings( 1024, 650, "eepp - TextView Wrapped Selection", WindowStyle::Default,
|
|
WindowBackend::Default, 32, {}, 1, false, true ),
|
|
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(),
|
|
1.5f ) );
|
|
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
|
std::string buffer;
|
|
FileSystem::fileGet( "assets/textfiles/lorem-ipsum.uext", buffer );
|
|
auto textView = UITextView::New();
|
|
textView->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::WrapContent );
|
|
textView->setPixelsSize( app.getUI()->getPixelsSize() );
|
|
textView->setText( buffer );
|
|
textView->setWordWrap( true );
|
|
textView->setTextSelectionEnabled( true );
|
|
textView->setTextSelectionRange( { 51, 286 } );
|
|
SceneManager::instance()->update();
|
|
SceneManager::instance()->draw();
|
|
compareImages( utest_state, utest_result, app.getWindow(),
|
|
"eepp-textview-wrapped-selection" );
|
|
};
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
UTEST( FontRendering, UITextViewWrappedSelection2 ) {
|
|
const auto runTest = [&]() {
|
|
UIApplication app(
|
|
WindowSettings( 1024, 650, "eepp - TextView Wrapped Selection", WindowStyle::Default,
|
|
WindowBackend::Default, 32, {}, 1, false, true ),
|
|
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(),
|
|
1.5f ) );
|
|
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
|
std::string buffer;
|
|
FileSystem::fileGet( "assets/textfiles/quota.uext", buffer );
|
|
auto textView = UITextView::New();
|
|
textView->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::WrapContent );
|
|
textView->setPixelsSize( app.getUI()->getPixelsSize() );
|
|
textView->setText( buffer );
|
|
textView->setWordWrap( true );
|
|
textView->setTextSelectionEnabled( true );
|
|
textView->setTextSelectionRange( { 51, 286 } );
|
|
SceneManager::instance()->update();
|
|
SceneManager::instance()->draw();
|
|
compareImages( utest_state, utest_result, app.getWindow(),
|
|
"eepp-textview-wrapped-selection-2" );
|
|
};
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
UTEST( FontRendering, TextSoftWrapPos ) {
|
|
const auto runTest = [&]() {
|
|
UIApplication app(
|
|
WindowSettings( 1024, 768, "eepp - Text Soft Wrap Pos", WindowStyle::Default,
|
|
WindowBackend::Default, 32, {}, 1, false, true ),
|
|
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) );
|
|
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
|
|
|
FontTrueType* font = FontTrueType::New( "DejaVuSansMono" );
|
|
font->loadFromFile( "../assets/fonts/DejaVuSansMono.ttf" );
|
|
|
|
Text text;
|
|
text.setFont( font );
|
|
text.setFontSize( 20 );
|
|
text.setString( "This is a long string that should wrap when the width is restricted." );
|
|
text.setColor( Color::White );
|
|
text.setLineWrapMode( LineWrapMode::Word );
|
|
text.setMaxWrapWidth( 200.f );
|
|
|
|
Vector2f pos = text.findCharacterPos( 30 );
|
|
EXPECT_GT( pos.y, 0.f );
|
|
|
|
Float vspace = text.getFont()->getLineSpacing( text.getCharacterSize() );
|
|
Vector2i queryPos( 10, (int)vspace + 5 );
|
|
Int32 foundIndex = text.findCharacterFromPos( queryPos );
|
|
|
|
EXPECT_GT( foundIndex, (Int32)14 );
|
|
|
|
Vector2f foundPos = text.findCharacterPos( foundIndex );
|
|
EXPECT_GT( foundPos.y, 0.f );
|
|
};
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
UTEST( FontRendering, TextSelection ) {
|
|
auto win = Engine::instance()->createWindow(
|
|
WindowSettings( 1024, 650, "eepp - Text Selection", WindowStyle::Default,
|
|
WindowBackend::Default, 32, {}, 1, false, true ) );
|
|
ASSERT_TRUE_MSG( win->isOpen(), "Failed to create Window" );
|
|
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
|
|
|
Text::TextShaperEnabled = false;
|
|
|
|
FontTrueType* font = FontTrueType::New( "NotoSans-Regular" );
|
|
bool loaded = font->loadFromFile( "../assets/fonts/NotoSans-Regular.ttf" );
|
|
ASSERT_TRUE( loaded );
|
|
FontFamily::loadFromRegular( font );
|
|
|
|
FontStyleConfig config;
|
|
config.Font = font;
|
|
config.CharacterSize = 20;
|
|
config.FontColor = Color::Black;
|
|
config.Style = Text::Regular;
|
|
|
|
String txt( "Line 1\nLine 2 is longer\nLine 3" );
|
|
|
|
Text text;
|
|
text.setStyleConfig( config );
|
|
text.setString( txt );
|
|
|
|
// Test 1: Single line selection (Line 1)
|
|
{
|
|
auto rects = text.getSelectionRects( { 0, 4 } ); // "Line"
|
|
EXPECT_EQ( 1ul, rects.size() );
|
|
if ( !rects.empty() ) {
|
|
EXPECT_EQ( 0, rects[0].Top );
|
|
EXPECT_GT( rects[0].getWidth(), 0 );
|
|
EXPECT_EQ( text.findCharacterPos( 0 ).x, rects[0].Left );
|
|
EXPECT_EQ( text.findCharacterPos( 4 ).x, rects[0].Right );
|
|
}
|
|
}
|
|
|
|
// Test 2: Multi-line selection (Line 1 to Line 2)
|
|
{
|
|
// "Line 1\nLine 2" -> Indices: "Line 1" (0-5), "\n" (6), "Line 2" (7-12)
|
|
// Select from index 2 ("n" in "Line 1") to index 9 ("i" in "Line 2")
|
|
auto rects = text.getSelectionRects( { 2, 9 } );
|
|
EXPECT_EQ( 2ul, rects.size() );
|
|
if ( rects.size() >= 2 ) {
|
|
// First line rect: From index 2 to end of line 1
|
|
EXPECT_EQ( text.findCharacterPos( 2 ).x, rects[0].Left );
|
|
EXPECT_GT( rects[0].Right, rects[0].Left );
|
|
|
|
// Second line rect: From start of line 2 to index 9
|
|
EXPECT_EQ( 0, rects[1].Left ); // Left aligned
|
|
EXPECT_EQ( text.findCharacterPos( 9 ).x, rects[1].Right );
|
|
}
|
|
}
|
|
|
|
// Test 3: Full selection
|
|
{
|
|
auto rects = text.getSelectionRects( { 0, static_cast<Int64>( txt.size() ) } );
|
|
EXPECT_EQ( 3ul, rects.size() );
|
|
}
|
|
|
|
// Test 4: Soft wrap
|
|
{
|
|
text.setLineWrapMode( LineWrapMode::Word );
|
|
text.setMaxWrapWidth( 50 ); // Force wrap
|
|
|
|
text.setString( "This is a very long string that should wrap multiple times." );
|
|
// Ensure layout is updated
|
|
text.getVisualLineCount();
|
|
|
|
EXPECT_GT( text.getVisualLineCount(), (Uint32)1 );
|
|
|
|
auto rects = text.getSelectionRects( { 0, static_cast<Int64>( text.getString().size() ) } );
|
|
EXPECT_EQ( (size_t)text.getVisualLineCount(), rects.size() );
|
|
}
|
|
|
|
Engine::destroySingleton();
|
|
}
|
|
|
|
UTEST( FontRendering, TextInitialOffset ) {
|
|
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
|
std::string loremIpsum;
|
|
FileSystem::fileGet( "assets/textfiles/lorem-ipsum.uext", loremIpsum );
|
|
String string( loremIpsum );
|
|
string.pop_back();
|
|
|
|
const auto runTest = [&]() {
|
|
auto win = Engine::instance()->createWindow(
|
|
WindowSettings( 512, 400, "eepp - Text Initial Offset", WindowStyle::Default,
|
|
WindowBackend::Default, 32, {}, 1, false, true ) );
|
|
|
|
ASSERT_TRUE_MSG( win->isOpen(), "Failed to create Window" );
|
|
|
|
win->setClearColor( RGB( 255, 255, 255 ) );
|
|
win->clear();
|
|
|
|
FontTrueType* font = FontTrueType::New( "NotoSans-Regular" );
|
|
font->loadFromFile( "../assets/fonts/NotoSans-Regular.ttf" );
|
|
|
|
Primitives p;
|
|
Float lw = p.getLineWidth();
|
|
p.setColor( Color::Red );
|
|
p.setFillMode( PrimitiveFillMode::DRAW_LINE );
|
|
|
|
// Test 1: Text with paragraph indent (initial X offset)
|
|
Float paragraphIndent = 40.f;
|
|
Float maxWidth = 400.f;
|
|
Vector2f pos{ 20, 20 };
|
|
|
|
Text text;
|
|
text.setFont( font );
|
|
text.setFontSize( 14 );
|
|
text.setColor( Color::Black );
|
|
text.setString( string );
|
|
text.setLineWrapMode( LineWrapMode::Word );
|
|
text.setMaxWrapWidth( maxWidth );
|
|
text.setInitialOffset( { paragraphIndent, 0 } );
|
|
p.drawPixelPerfectLineRectangle(
|
|
text.getLocalBounds().move( pos ).move( { -lw, -lw } ).enlarge( { lw * 2, lw * 2 } ) );
|
|
text.draw( pos.x, pos.y );
|
|
|
|
// Test 2: Text with Y offset (simulating a text block shifted down)
|
|
pos.y += text.getTextHeight() + 30;
|
|
text.setInitialOffset( { paragraphIndent * 2, 0 } ); // Larger indent
|
|
p.drawPixelPerfectLineRectangle(
|
|
text.getLocalBounds().move( pos ).move( { -lw, -lw } ).enlarge( { lw * 2, lw * 2 } ) );
|
|
text.draw( pos.x, pos.y );
|
|
|
|
compareImages( utest_state, utest_result, win, "eepp-text-initial-offset" );
|
|
|
|
Engine::destroySingleton();
|
|
};
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
UTEST( FontRendering, TextContiguousOffset ) {
|
|
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
|
|
|
const auto runTest = [&]() {
|
|
auto win = Engine::instance()->createWindow(
|
|
WindowSettings( 512, 300, "eepp - Text Contiguous Offset", WindowStyle::Default,
|
|
WindowBackend::Default, 32, {}, 1, false, true ) );
|
|
|
|
ASSERT_TRUE_MSG( win->isOpen(), "Failed to create Window" );
|
|
|
|
win->setClearColor( RGB( 255, 255, 255 ) );
|
|
win->clear();
|
|
|
|
FontTrueType* font = FontTrueType::New( "NotoSans-Regular" );
|
|
font->loadFromFile( "../assets/fonts/NotoSans-Regular.ttf" );
|
|
|
|
Float maxWidth = 450.f;
|
|
Vector2f pos{ 20, 20 };
|
|
Float paragraphIndent = 30.f;
|
|
|
|
Primitives p;
|
|
p.setColor( Color::Red );
|
|
Float lw = p.getLineWidth();
|
|
|
|
// Simulate RichText: Two contiguous Text instances
|
|
// First Text: "Hello " in black (with paragraph indent)
|
|
Text text1;
|
|
text1.setFont( font );
|
|
text1.setFontSize( 16 );
|
|
text1.setColor( Color::seagreen );
|
|
text1.setString( "Hello " );
|
|
text1.setInitialOffset( { paragraphIndent, 0 } );
|
|
text1.draw( pos.x, pos.y );
|
|
|
|
Float text1EndX = text1.getLastLineWidth();
|
|
|
|
// Second Text: "World! This is a long text that should wrap to a second visual line..."
|
|
// in red, continuing from text1's end position
|
|
Text text2;
|
|
text2.setFont( font );
|
|
text2.setFontSize( 16 );
|
|
text2.setColor( Color::darkmagenta );
|
|
text2.setString( "World! This is a RichText simulation where the second Text segment "
|
|
"continues from where the first left off and should wrap correctly "
|
|
"to multiple visual lines. The wrap should respect the initial offset." );
|
|
text2.setLineWrapMode( LineWrapMode::Word );
|
|
text2.setMaxWrapWidth( maxWidth );
|
|
text2.setInitialOffset( { text1EndX, 0 } ); // Continue from text1's end
|
|
text2.draw( pos.x, pos.y );
|
|
|
|
p.drawPixelPerfectLineRectangle( text1.getLocalBounds()
|
|
.move( pos )
|
|
.expand( text2.getLocalBounds().move( pos ) )
|
|
.move( { -lw, -lw } )
|
|
.enlarge( { lw * 2, lw * 2 } ) );
|
|
|
|
// Verify the second text wrapped
|
|
EXPECT_GT( text2.getVisualLineCount(), (Uint32)1 );
|
|
|
|
// Second example: Without paragraph indent
|
|
pos.y += text2.getTextHeight() + 30;
|
|
|
|
Text text3;
|
|
text3.setFont( font );
|
|
text3.setFontSize( 16 );
|
|
text3.setColor( Color::Blue );
|
|
text3.setString( "Start: " );
|
|
text3.draw( pos.x, pos.y );
|
|
|
|
Float text3EndX = text3.getLastLineWidth();
|
|
|
|
Text text4;
|
|
text4.setFont( font );
|
|
text4.setFontSize( 16 );
|
|
text4.setColor( Color::darkorchid );
|
|
text4.setString( "This text continues from \"Start: \" and also wraps to show "
|
|
"that the initial X offset is correctly applied only to the first "
|
|
"visual line, while subsequent lines start at x=0." );
|
|
text4.setLineWrapMode( LineWrapMode::Word );
|
|
text4.setMaxWrapWidth( maxWidth );
|
|
text4.setInitialOffset( { text3EndX, 0 } );
|
|
text4.draw( pos.x, pos.y );
|
|
|
|
p.drawPixelPerfectLineRectangle( text3.getLocalBounds()
|
|
.move( pos )
|
|
.expand( text4.getLocalBounds().move( pos ) )
|
|
.move( { -lw, -lw } )
|
|
.enlarge( { lw * 2, lw * 2 } ) );
|
|
|
|
EXPECT_GT( text4.getVisualLineCount(), (Uint32)1 );
|
|
|
|
compareImages( utest_state, utest_result, win, "eepp-text-contiguous-offset" );
|
|
|
|
Engine::destroySingleton();
|
|
};
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
UTEST( FontRendering, TextBackgroundColor ) {
|
|
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
|
|
|
const auto runTest = [&]() {
|
|
auto win = Engine::instance()->createWindow(
|
|
WindowSettings( 512, 400, "eepp - Text Background Color", WindowStyle::Default,
|
|
WindowBackend::Default, 32, {}, 1, false, true ) );
|
|
|
|
ASSERT_TRUE_MSG( win->isOpen(), "Failed to create Window" );
|
|
|
|
win->setClearColor( RGB( 255, 255, 255 ) );
|
|
win->clear();
|
|
|
|
FontTrueType* font = FontTrueType::New( "NotoSans-Regular" );
|
|
font->loadFromFile( "../assets/fonts/NotoSans-Regular.ttf" );
|
|
|
|
Vector2f pos{ 20, 20 };
|
|
Text text;
|
|
text.setFont( font );
|
|
text.setFontSize( 20 );
|
|
text.setFillColor( Color::Black );
|
|
text.setBackgroundColor( Color::Yellow );
|
|
text.setString( "Text with background color\nand multiple lines." );
|
|
text.draw( pos.x, pos.y );
|
|
|
|
pos.y += text.getTextHeight() + 20;
|
|
text.setAlign( TEXT_ALIGN_CENTER );
|
|
text.setString( "Centered text with\nbackground color." );
|
|
text.draw( pos.x, pos.y );
|
|
|
|
pos.y += text.getTextHeight() + 20;
|
|
text.setAlign( TEXT_ALIGN_LEFT );
|
|
text.setLineWrapMode( LineWrapMode::Word );
|
|
text.setMaxWrapWidth( 200 );
|
|
text.setString(
|
|
"Wrapped text with background color that should only cover the text area." );
|
|
text.draw( pos.x, pos.y );
|
|
|
|
pos.y += text.getTextHeight() + 20;
|
|
text.setLineWrapMode( LineWrapMode::NoWrap );
|
|
text.setBackgroundColor( Color::cyan );
|
|
text.setString( " " ); // Only spaces
|
|
text.draw( pos.x, pos.y );
|
|
|
|
compareImages( utest_state, utest_result, win, "eepp-text-background-color" );
|
|
|
|
Engine::destroySingleton();
|
|
};
|
|
|
|
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();
|
|
}
|
|
}
|