diff --git a/bin/emscripten-fs.html b/bin/emscripten-fs.html index a10d264a6..41565b144 100644 --- a/bin/emscripten-fs.html +++ b/bin/emscripten-fs.html @@ -1,4 +1,5 @@ + @@ -63,7 +64,7 @@ function getDemoScript(name) { if (name) return name; - return "eepp-test-debug.js"; + return "ecode.js"; } function getParameter(name) { @@ -108,8 +109,9 @@ monitorRunDependencies: function(left) { // no run dependencies to log }, - }; - window.onerror = function() { + arguments: window.location.search.substr(1).split('&') + }; + window.onerror = function() { console.log("onerror: " + event); }; diff --git a/include/eepp/graphics/fonttruetype.hpp b/include/eepp/graphics/fonttruetype.hpp index 2cf2b443b..928400e09 100644 --- a/include/eepp/graphics/fonttruetype.hpp +++ b/include/eepp/graphics/fonttruetype.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace EE { namespace System { class Pack; @@ -65,10 +66,14 @@ class EE_API FontTrueType : public Font { bool isMonospace() const; - bool isEmojiFont() const { return mIsEmojiFont; } + bool isEmojiFont() const; bool hasGlyph( Uint32 codePoint ) const; + void setIsColorEmojiFont( bool isColorEmojiFont ); + + void setIsEmojiFont( bool isEmojiFont ); + protected: explicit FontTrueType( const std::string& FontName ); @@ -85,7 +90,7 @@ class EE_API FontTrueType : public Font { typedef std::map GlyphDrawableTable; struct Page { - Page(); + Page( const Uint32 fontInternalId ); ~Page(); @@ -95,6 +100,7 @@ class EE_API FontTrueType : public Font { Texture* texture; ///< Texture containing the pixels of the glyphs unsigned int nextRow; ///< Y position of the next new row in the texture std::vector rows; ///< List containing the position of all the existing rows + Uint32 fontInternalId{ 0 }; }; void cleanup(); @@ -106,6 +112,8 @@ class EE_API FontTrueType : public Font { const Glyph& getGlyph( Uint32 codePoint, unsigned int characterSize, bool bold, Float outlineThickness, Page& page, const Float& forzeSize ) const; + Uint32 getGlyphIndex( const Uint32& codePoint ) const; + Glyph loadGlyph( Uint32 codePoint, unsigned int characterSize, bool bold, Float outlineThickness, Page& page, const Float& forceSize = 0.f ) const; @@ -113,7 +121,9 @@ class EE_API FontTrueType : public Font { bool setCurrentSize( unsigned int characterSize ) const; - typedef std::map + Page& getPage( unsigned int characterSize ) const; + + typedef std::map> PageTable; ///< Table mapping a character size to its page (texture) void* mLibrary; ///< Pointer to the internal library interface (it is typeless to avoid exposing @@ -134,8 +144,10 @@ class EE_API FontTrueType : public Font { bool mIsColorEmojiFont{ false }; bool mIsEmojiFont{ false }; mutable std::map mClosestCharacterSize; + mutable std::map mCodePointIndexCache; - Uint64 getIndexKey( Uint32 index, bool bold, Float outlineThickness ) const; + Uint64 getIndexKey( Uint32 fontInternalId, Uint32 index, bool bold, + Float outlineThickness ) const; }; }} // namespace EE::Graphics diff --git a/src/eepp/graphics/font.cpp b/src/eepp/graphics/font.cpp index 344f8e82c..97d6d5b68 100644 --- a/src/eepp/graphics/font.cpp +++ b/src/eepp/graphics/font.cpp @@ -12,9 +12,9 @@ bool Font::isEmojiCodePoint( const Uint32& codePoint ) { const Uint32 rangeMax2 = 127569; const Uint32 rangeMin3 = 8987; const Uint32 rangeMax3 = 12953; - return ( ( rangeMin <= codePoint && codePoint <= rangeMax ) || - ( rangeMin2 <= codePoint && codePoint <= rangeMax2 ) || - ( rangeMin3 <= codePoint && codePoint <= rangeMax3 ) ); + return codePoint > 8987 && ( ( rangeMin <= codePoint && codePoint <= rangeMax ) || + ( rangeMin2 <= codePoint && codePoint <= rangeMax2 ) || + ( rangeMin3 <= codePoint && codePoint <= rangeMax3 ) ); } bool Font::containsEmojiCodePoint( const String& string ) { diff --git a/src/eepp/graphics/fonttruetype.cpp b/src/eepp/graphics/fonttruetype.cpp index 3112dd5a3..6e52cca59 100644 --- a/src/eepp/graphics/fonttruetype.cpp +++ b/src/eepp/graphics/fonttruetype.cpp @@ -14,6 +14,7 @@ #include FT_BITMAP_H #include FT_STROKER_H #include FT_TRUETYPE_TABLES_H +#include #include #include @@ -43,8 +44,10 @@ template inline T reinterpret( const U& input ) { } // Combine outline thickness, boldness and font glyph index into a single 64-bit key -EE::Uint64 combine( float outlineThickness, bool bold, EE::Uint32 index ) { - return ( static_cast( reinterpret( outlineThickness * 100 ) ) << 33 ) | +EE::Uint64 combine( float outlineThickness, bool bold, EE::Uint32 index, + EE::Uint32 fontInternalId ) { + return ( static_cast( reinterpret( fontInternalId ) ) << 48 ) | + ( static_cast( reinterpret( outlineThickness * 100 ) ) << 33 ) | ( static_cast( bold ) << 32 ) | index; } @@ -52,6 +55,9 @@ EE::Uint64 combine( float outlineThickness, bool bold, EE::Uint32 index ) { namespace EE { namespace Graphics { +static std::map fontsInternalIds; +static std::atomic fontInternalIdCounter{ 0 }; + FontTrueType* FontTrueType::New( const std::string& FontName ) { return eeNew( FontTrueType, ( FontName ) ); } @@ -156,6 +162,10 @@ bool FontTrueType::loadFromFile( const std::string& filename ) { // Store the font information mInfo.family = face->family_name ? face->family_name : std::string(); + auto fontInternalId = fontsInternalIds.find( mInfo.family ); + if ( fontsInternalIds.end() == fontInternalId ) + fontsInternalIds[mInfo.family] = ++fontInternalIdCounter; + sendEvent( Event::Load ); return true; @@ -226,6 +236,10 @@ bool FontTrueType::loadFromMemory( const void* data, std::size_t sizeInBytes, bo // Store the font information mInfo.family = face->family_name ? face->family_name : std::string(); + auto fontInternalId = fontsInternalIds.find( mInfo.family ); + if ( fontsInternalIds.end() == fontInternalId ) + fontsInternalIds[mInfo.family] = ++fontInternalIdCounter; + sendEvent( Event::Load ); return true; @@ -309,6 +323,10 @@ bool FontTrueType::loadFromStream( IOStream& stream ) { // Store the font information mInfo.family = face->family_name ? face->family_name : std::string(); + auto fontInternalId = fontsInternalIds.find( mInfo.family ); + if ( fontsInternalIds.end() == fontInternalId ) + fontsInternalIds[mInfo.family] = ++fontInternalIdCounter; + sendEvent( Event::Load ); return true; @@ -333,18 +351,30 @@ const FontTrueType::Info& FontTrueType::getInfo() const { return mInfo; } -Uint64 FontTrueType::getIndexKey( Uint32 index, bool bold, Float outlineThickness ) const { - return combine( outlineThickness, bold, index ); +Uint64 FontTrueType::getIndexKey( Uint32 fontInternalId, Uint32 index, bool bold, + Float outlineThickness ) const { + return combine( outlineThickness, bold, index, fontInternalId ); } bool FontTrueType::hasGlyph( Uint32 codePoint ) const { - return FT_Get_Char_Index( static_cast( mFace ), codePoint ) != 0; + return getGlyphIndex( codePoint ) != 0; +} + +Uint32 FontTrueType::getGlyphIndex( const Uint32& codePoint ) const { + Uint32 index; + auto indexIter = mCodePointIndexCache.find( codePoint ); + if ( mCodePointIndexCache.end() != indexIter ) { + index = indexIter->second; + } else { + index = FT_Get_Char_Index( static_cast( mFace ), codePoint ); + mCodePointIndexCache[codePoint] = index; + } + return index; } const Glyph& FontTrueType::getGlyph( Uint32 codePoint, unsigned int characterSize, bool bold, Float outlineThickness ) const { - FT_Face face = static_cast( mFace ); - Uint32 index = FT_Get_Char_Index( face, codePoint ); + Uint32 index = getGlyphIndex( codePoint ); if ( Font::isEmojiCodePoint( codePoint ) && !mIsColorEmojiFont && !mIsEmojiFont ) { if ( !mIsColorEmojiFont && FontManager::instance()->getColorEmojiFont() != nullptr && @@ -360,7 +390,7 @@ const Glyph& FontTrueType::getGlyph( Uint32 codePoint, unsigned int characterSiz FontTrueType* fontEmoji = static_cast( FontManager::instance()->getColorEmojiFont() ); return fontEmoji->getGlyph( codePoint, characterSize, bold, outlineThickness, - mPages[characterSize], maxWidth ); + getPage( characterSize ), maxWidth ); } else if ( !mIsEmojiFont && FontManager::instance()->getEmojiFont() != nullptr && FontManager::instance()->getEmojiFont()->getType() == FontType::TTF ) { @@ -370,11 +400,10 @@ const Glyph& FontTrueType::getGlyph( Uint32 codePoint, unsigned int characterSiz Glyph monospaceGlyph = getGlyph( ' ', characterSize, bold, outlineThickness ); maxWidth = monospaceGlyph.advance; } - FontTrueType* fontEmoji = static_cast( FontManager::instance()->getEmojiFont() ); return fontEmoji->getGlyph( codePoint, characterSize, bold, outlineThickness, - mPages[characterSize], maxWidth ); + getPage( characterSize ), maxWidth ); } } @@ -384,8 +413,7 @@ const Glyph& FontTrueType::getGlyph( Uint32 codePoint, unsigned int characterSiz const Glyph& FontTrueType::getGlyph( Uint32 codePoint, unsigned int characterSize, bool bold, Float outlineThickness, Page& page, const Float& forzeSize ) const { - FT_Face face = static_cast( mFace ); - Uint32 index = FT_Get_Char_Index( face, codePoint ); + Uint32 index = getGlyphIndex( codePoint ); return getGlyphByIndex( index, characterSize, bold, outlineThickness, page, forzeSize ); } @@ -396,7 +424,7 @@ const Glyph& FontTrueType::getGlyphByIndex( Uint32 index, unsigned int character GlyphTable& glyphs = page.glyphs; // Build the key by combining the code point, bold flag, and outline thickness - Uint64 key = getIndexKey( index, bold, outlineThickness ); + Uint64 key = getIndexKey( fontsInternalIds[mInfo.family], index, bold, outlineThickness ); // Search the glyph into the cache GlyphTable::const_iterator it = glyphs.find( key ); @@ -413,22 +441,23 @@ const Glyph& FontTrueType::getGlyphByIndex( Uint32 index, unsigned int character const Glyph& FontTrueType::getGlyphByIndex( Uint32 index, unsigned int characterSize, bool bold, Float outlineThickness ) const { - return getGlyphByIndex( index, characterSize, bold, outlineThickness, mPages[characterSize], + return getGlyphByIndex( index, characterSize, bold, outlineThickness, getPage( characterSize ), 0.f ); } GlyphDrawable* FontTrueType::getGlyphDrawable( Uint32 codePoint, unsigned int characterSize, bool bold, Float outlineThickness ) const { - GlyphDrawableTable& drawables = mPages[characterSize].drawables; + GlyphDrawableTable& drawables = getPage( characterSize ).drawables; - Uint64 key = getIndexKey( codePoint, bold, outlineThickness ); + Uint64 key = getIndexKey( getPage( characterSize ).fontInternalId, getGlyphIndex( codePoint ), + bold, outlineThickness ); auto it = drawables.find( key ); if ( it != drawables.end() ) { return it->second; } else { const Glyph& glyph = getGlyph( codePoint, characterSize, bold, outlineThickness ); - auto& page = mPages[characterSize]; + auto& page = getPage( characterSize ); GlyphDrawable* region = GlyphDrawable::New( page.texture, glyph.textureRect, String::format( "%s_%d_%u", mFontName.c_str(), characterSize, codePoint ) ); @@ -442,15 +471,15 @@ GlyphDrawable* FontTrueType::getGlyphDrawable( Uint32 codePoint, unsigned int ch Float FontTrueType::getKerning( Uint32 first, Uint32 second, unsigned int characterSize, bool bold ) const { // Special case where first or second is 0 (null character) - if ( first == 0 || second == 0 ) + if ( first == 0 || second == 0 || isMonospace() ) return 0.f; FT_Face face = static_cast( mFace ); if ( face && setCurrentSize( characterSize ) ) { // Convert the characters to indices - FT_UInt index1 = FT_Get_Char_Index( face, first ); - FT_UInt index2 = FT_Get_Char_Index( face, second ); + FT_UInt index1 = getGlyphIndex( first ); + FT_UInt index2 = getGlyphIndex( second ); // Retrieve position compensation deltas generated by FT_LOAD_FORCE_AUTOHINT flag auto firstRsbDelta = static_cast( getGlyph( first, characterSize, bold ).rsbDelta ); @@ -543,7 +572,7 @@ Float FontTrueType::getUnderlineThickness( unsigned int characterSize ) const { } Texture* FontTrueType::getTexture( unsigned int characterSize ) const { - return mPages[characterSize].texture; + return getPage( characterSize ).texture; } bool FontTrueType::loaded() const { @@ -998,6 +1027,24 @@ bool FontTrueType::setCurrentSize( unsigned int characterSize ) const { } } +FontTrueType::Page& FontTrueType::getPage( unsigned int characterSize ) const { + auto pageIt = mPages.find( characterSize ); + if ( pageIt == mPages.end() ) { + mPages.insert( std::make_pair( characterSize, + std::make_unique( fontsInternalIds[mInfo.family] ) ) ); + pageIt = mPages.find( characterSize ); + } + return *pageIt->second; +} + +void FontTrueType::setIsEmojiFont( bool isEmojiFont ) { + mIsEmojiFont = isEmojiFont; +} + +void FontTrueType::setIsColorEmojiFont( bool isColorEmojiFont ) { + mIsColorEmojiFont = isColorEmojiFont; +} + bool FontTrueType::isColorEmojiFont() const { return mIsColorEmojiFont; } @@ -1006,6 +1053,10 @@ bool FontTrueType::isMonospace() const { return FT_IS_FIXED_WIDTH( static_cast( mFace ) ); } +bool FontTrueType::isEmojiFont() const { + return mIsEmojiFont; +} + bool FontTrueType::getBoldAdvanceSameAsRegular() const { return mBoldAdvanceSameAsRegular; } @@ -1014,7 +1065,8 @@ void FontTrueType::setBoldAdvanceSameAsRegular( bool boldAdvanceSameAsRegular ) mBoldAdvanceSameAsRegular = boldAdvanceSameAsRegular; } -FontTrueType::Page::Page() : texture( NULL ), nextRow( 3 ) { +FontTrueType::Page::Page( const Uint32 fontInternalId ) : + texture( NULL ), nextRow( 3 ), fontInternalId( fontInternalId ) { // Make sure that the texture is initialized by default Image image; image.create( 128, 128, 4 ); diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index 5c8d6dc6f..786eb2b83 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -2060,6 +2060,10 @@ void App::initProjectTreeView( const std::string& path ) { if ( !path.empty() ) { if ( FileSystem::isDirectory( path ) ) { loadFolder( path ); + } else if ( String::startsWith( path, "https://" ) || + String::startsWith( path, "http://" ) ) { + loadFolder( "." ); + loadFileFromPath( path, false ); } else { std::string rpath( FileSystem::getRealPath( path ) ); std::string folderPath( FileSystem::fileRemoveFileName( rpath ) ); @@ -2134,8 +2138,7 @@ FontTrueType* App::loadFont( const std::string& name, std::string fontPath, return FontTrueType::New( name, fontPath ); } -void App::init( const std::string& file, const Float& pidelDensity, - const std::string& colorScheme ) { +void App::init( std::string file, const Float& pidelDensity, const std::string& colorScheme ) { DisplayManager* displayManager = Engine::instance()->getDisplayManager(); Display* currentDisplay = displayManager->getDisplayIndex( 0 ); mDisplayDPI = currentDisplay->getDPI(); @@ -2550,20 +2553,44 @@ void App::init( const std::string& file, const Float& pidelDensity, mConsole = eeNew( Console, ( mFontMono, true, true, 1024 * 1000, 0, mWindow ) ); +#if EE_PLATFORM == EE_PLATFORM_EMSCRIPTEN + if ( file == "./this.program" ) + file = ""; +#endif + initProjectTreeView( file ); #if EE_PLATFORM == EE_PLATFORM_EMSCRIPTEN - downloadFileWeb( "https://raw.githubusercontent.com/SpartanJ/eepp/develop/README.md" ); + if ( file.empty() ) + downloadFileWeb( "https://raw.githubusercontent.com/SpartanJ/eepp/develop/README.md" ); #endif mWindow->runMainLoop( &appLoop ); } } +#if EE_PLATFORM == EE_PLATFORM_EMSCRIPTEN +std::vector parseEmscriptenArgs( int argc, char* argv[] ) { + std::vector args; + args.emplace_back( argv[0] ); + for ( int i = 1; i < argc; i++ ) { + auto split = String::split( std::string( argv[i] ), '=' ); + if ( split.size() == 2 ) { + std::string arg( split[0] + "=" + URI::decode( split[1] ) ); + args.emplace_back( !String::startsWith( arg, "--" ) ? ( std::string( "--" ) + arg ) + : arg ); + } + } + return args; +} +#endif + EE_MAIN_FUNC int main( int argc, char* argv[] ) { args::ArgumentParser parser( "ecode" ); args::HelpFlag help( parser, "help", "Display this help menu", { 'h', "help" } ); - args::Positional file( parser, "file", "The file path" ); + args::Positional file( parser, "file", "The file or folder path" ); + args::ValueFlag filePos( parser, "file", "The file or folder path", + { 'f', "file", "folder" } ); args::ValueFlag pixelDenstiyConf( parser, "pixel-density", "Set default application pixel density", { 'd', "pixel-density" } ); @@ -2572,7 +2599,11 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) { { 'c', "prefers-color-scheme" } ); try { +#if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN parser.ParseCLI( argc, argv ); +#else + parser.ParseCLI( parseEmscriptenArgs( argc, argv ) ); +#endif } catch ( const args::Help& ) { std::cout << parser; return EXIT_SUCCESS; @@ -2587,7 +2618,8 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) { } appInstance = eeNew( App, () ); - appInstance->init( file.Get(), pixelDenstiyConf ? pixelDenstiyConf.Get() : 0.f, + appInstance->init( filePos ? filePos.Get() : file.Get(), + pixelDenstiyConf ? pixelDenstiyConf.Get() : 0.f, prefersColorScheme ? prefersColorScheme.Get() : "" ); eeSAFE_DELETE( appInstance ); diff --git a/src/tools/ecode/ecode.hpp b/src/tools/ecode/ecode.hpp index 36944576f..094cd2349 100644 --- a/src/tools/ecode/ecode.hpp +++ b/src/tools/ecode/ecode.hpp @@ -24,7 +24,7 @@ class App : public UICodeEditorSplitter::Client { ~App(); - void init( const std::string& file, const Float& pidelDensity, const std::string& colorScheme ); + void init( std::string file, const Float& pidelDensity, const std::string& colorScheme ); void setAppTitle( const std::string& title );