diff --git a/bin/unit_tests/assets/html/base.css b/bin/unit_tests/assets/html/base.css index 39496aec7..ce116e654 100644 --- a/bin/unit_tests/assets/html/base.css +++ b/bin/unit_tests/assets/html/base.css @@ -1,8 +1,4 @@ body { - margin-top: 8px; - margin-right: 8px; - margin-bottom: 8px; - margin-left: 8px; font-size: 11px; color: black; background-color: white; diff --git a/bin/unit_tests/assets/html/eepp-uihtmltable-complex-layout-2.webp b/bin/unit_tests/assets/html/eepp-uihtmltable-complex-layout-2.webp index 5808b4cb1..f658020cb 100644 Binary files a/bin/unit_tests/assets/html/eepp-uihtmltable-complex-layout-2.webp and b/bin/unit_tests/assets/html/eepp-uihtmltable-complex-layout-2.webp differ diff --git a/bin/unit_tests/assets/html/eepp-uihtmltable-complex-layout-3.webp b/bin/unit_tests/assets/html/eepp-uihtmltable-complex-layout-3.webp index 4c2090c4d..340f7f8ee 100644 Binary files a/bin/unit_tests/assets/html/eepp-uihtmltable-complex-layout-3.webp and b/bin/unit_tests/assets/html/eepp-uihtmltable-complex-layout-3.webp differ diff --git a/bin/unit_tests/assets/html/eepp-uihtmltable-complex-layout.webp b/bin/unit_tests/assets/html/eepp-uihtmltable-complex-layout.webp index 122f4cd9a..94304b935 100644 Binary files a/bin/unit_tests/assets/html/eepp-uihtmltable-complex-layout.webp and b/bin/unit_tests/assets/html/eepp-uihtmltable-complex-layout.webp differ diff --git a/include/eepp/graphics/drawablesearcher.hpp b/include/eepp/graphics/drawablesearcher.hpp index 57d413e6f..81efb4da8 100644 --- a/include/eepp/graphics/drawablesearcher.hpp +++ b/include/eepp/graphics/drawablesearcher.hpp @@ -3,12 +3,14 @@ #include #include +#include namespace EE { namespace Graphics { class EE_API DrawableSearcher { public: - static Drawable* searchByName( const std::string& name, bool firstSearchSprite = false ); + static Drawable* searchByName( const std::string& name, bool firstSearchSprite = false, + Network::URI referer = "" ); static Drawable* searchById( const Uint32& id ); diff --git a/include/eepp/network/http.hpp b/include/eepp/network/http.hpp index d05b74a94..f9c6d22ce 100644 --- a/include/eepp/network/http.hpp +++ b/include/eepp/network/http.hpp @@ -115,6 +115,9 @@ class EE_API Http : NonCopyable { ** @return Status code of the response */ Status getStatus() const; + /** @return True if the response status is successful (2XX status) */ + bool isOK() const; + /** @brief Get the response status description */ const char* getStatusDescription() const; diff --git a/include/eepp/ui/css/stylesheetlength.hpp b/include/eepp/ui/css/stylesheetlength.hpp index 8e8a4b542..a1495a840 100644 --- a/include/eepp/ui/css/stylesheetlength.hpp +++ b/include/eepp/ui/css/stylesheetlength.hpp @@ -33,6 +33,7 @@ class EE_API StyleSheetLength { Dprd, Dpru, Dpr, + Ch, }; static Unit unitFromString( std::string unitStr ); diff --git a/include/eepp/ui/uiscenenode.hpp b/include/eepp/ui/uiscenenode.hpp index 71d73a101..5dc830291 100644 --- a/include/eepp/ui/uiscenenode.hpp +++ b/include/eepp/ui/uiscenenode.hpp @@ -715,6 +715,9 @@ class EE_API UISceneNode : public SceneNode { */ URI solveRelativePath( URI uri, URI baseURI = {} ); + /** @return The document referer */ + URI getReferer() const { return mReferer; }; + protected: friend class EE::UI::UIWindow; friend class EE::UI::UIWidget; @@ -743,6 +746,7 @@ class EE_API UISceneNode : public SceneNode { Uint32 mCurOnSizeChangeListener{ 0 }; std::shared_ptr mThreadPool; URI mURI; + URI mReferer; std::function mURLInterceptorCb; /** @@ -957,8 +961,7 @@ class EE_API UISceneNode : public SceneNode { /** @return The document / scene URI used to resolve paths from a complete URI (with * path+query+fragment+etc) */ - URI getURIFromURL( const URI& url ); - + URI getURIFromURL( const URI& url ) const; }; }} // namespace EE::UI diff --git a/src/eepp/graphics/drawablesearcher.cpp b/src/eepp/graphics/drawablesearcher.cpp index 132a644cd..78f80a80a 100644 --- a/src/eepp/graphics/drawablesearcher.cpp +++ b/src/eepp/graphics/drawablesearcher.cpp @@ -107,7 +107,8 @@ static Drawable* parseDataURI( const std::string& name ) { return drawable; } -Drawable* DrawableSearcher::searchByName( const std::string& name, bool firstSearchSprite ) { +Drawable* DrawableSearcher::searchByName( const std::string& name, bool firstSearchSprite, + Network::URI referer ) { Drawable* drawable = NULL; if ( name.size() ) { @@ -147,12 +148,12 @@ Drawable* DrawableSearcher::searchByName( const std::string& name, bool firstSea } else if ( String::startsWith( name, "file://" ) ) { std::string filePath( name.substr( 7 ) ); - #if EE_PLATFORM == EE_PLATFORM_WIN +#if EE_PLATFORM == EE_PLATFORM_WIN if ( filePath.size() >= 3 && filePath[0] == '/' && String::isLetter( filePath[1] ) && filePath[2] == ':' ) { filePath = filePath.substr( 1 ); } - #endif +#endif drawable = TextureFactory::instance()->getByName( filePath ); @@ -171,17 +172,25 @@ Drawable* DrawableSearcher::searchByName( const std::string& name, bool firstSea 1, 1, 4, Color::Transparent, false, Texture::ClampMode::ClampToEdge, false, false, name ); + std::map headers; + if ( !referer.empty() ) + headers["referer"] = referer.toString(); + Http::getAsync( - [texture]( const Http&, Http::Request&, Http::Response& response ) { - if ( !response.getBody().empty() ) { + [texture, name]( const Http&, Http::Request&, Http::Response& response ) { + if ( response.isOK() && !response.getBody().empty() ) { Image image( (const Uint8*)&response.getBody()[0], response.getBody().size() ); if ( image.getPixels() != NULL ) texture->replace( &image ); + } else { + Log::debug( "DrawableSearcher::searchByName: could not download image: " + "%s. Error: %d\n%s", + name, response.getStatus(), response.getBody() ); } }, - URI( name ), Seconds( 5 ) ); + URI( name ), Seconds( 5 ), {}, headers ); } drawable = texture; diff --git a/src/eepp/network/http.cpp b/src/eepp/network/http.cpp index d2f22400b..bc10ff621 100644 --- a/src/eepp/network/http.cpp +++ b/src/eepp/network/http.cpp @@ -469,6 +469,10 @@ Http::Response::Status Http::Response::getStatus() const { return mStatus; } +bool Http::Response::isOK() const { + return mStatus >= 200 && mStatus < 300; +} + const char* Http::Response::getStatusDescription() const { switch ( mStatus ) { // 2xx: success diff --git a/src/eepp/ui/css/drawableimageparser.cpp b/src/eepp/ui/css/drawableimageparser.cpp index 91a89538b..06f852692 100644 --- a/src/eepp/ui/css/drawableimageparser.cpp +++ b/src/eepp/ui/css/drawableimageparser.cpp @@ -36,7 +36,8 @@ Drawable* DrawableImageParser::createDrawable( const std::string& value, const S if ( !functionType.isEmpty() ) { if ( exists( functionType.getName() ) ) return mFuncs[functionType.getName()]( functionType, size, ownIt, node ); - } else if ( NULL != ( res = DrawableSearcher::searchByName( value ) ) ) { + } else if ( NULL != ( res = DrawableSearcher::searchByName( + value, false, node->getUISceneNode()->getReferer() ) ) ) { if ( res->getDrawableType() == Drawable::SPRITE ) ownIt = true; return res; @@ -334,7 +335,8 @@ void DrawableImageParser::registerBaseParsers() { return DrawableSearcher::searchByName( node->getUISceneNode() ->solveRelativePath( functionType.getParameters().at( 0 ) ) - .toString() ); + .toString(), + false, node->getUISceneNode()->getReferer() ); }; mFuncs["icon"] = []( const FunctionString& functionType, const Sizef& size, bool&, diff --git a/src/eepp/ui/css/mediaquery.cpp b/src/eepp/ui/css/mediaquery.cpp index dff7d4182..974a7e92e 100644 --- a/src/eepp/ui/css/mediaquery.cpp +++ b/src/eepp/ui/css/mediaquery.cpp @@ -94,14 +94,7 @@ MediaQuery::ptr MediaQuery::parse( const std::string& str ) { StyleSheetLength length = StyleSheetLength::fromString( exprTokens[1] ); expr.valStr = String::toLower( exprTokens[1] ); - - if ( length.getUnit() == StyleSheetLength::Unit::Dpcm || - length.getUnit() == StyleSheetLength::Unit::Dpi ) { - expr.val = (int)( length.getValue() * 2.54 ); - } else { - expr.val = (int)length.asPixels( 0, Sizef::Zero, dpi ); - } - + expr.val = (int)length.asPixels( 0, Sizef::Zero, dpi ); expr.fval = length.getValue(); } } diff --git a/src/eepp/ui/css/stylesheetlength.cpp b/src/eepp/ui/css/stylesheetlength.cpp index 7eaafccc2..76e47e948 100644 --- a/src/eepp/ui/css/stylesheetlength.cpp +++ b/src/eepp/ui/css/stylesheetlength.cpp @@ -30,6 +30,7 @@ enum UnitHashes : String::HashType { Dprd = String::hash( "dprd" ), Dpru = String::hash( "dpru" ), Dpr = String::hash( "dpr" ), + Ch = String::hash( "ch" ), }; enum PercentagePositions : String::HashType { @@ -116,6 +117,8 @@ StyleSheetLength::Unit StyleSheetLength::unitFromString( std::string unitStr ) { return Unit::Dpru; case UnitHashes::Dpr: return Unit::Dpr; + case UnitHashes::Ch: + return Unit::Ch; } return Unit::Dp; } @@ -162,6 +165,8 @@ std::string StyleSheetLength::unitToString( const StyleSheetLength::Unit& unit ) return "dpru"; case Unit::Dpr: return "dpr"; + case Unit::Ch: + return "ch"; } return "px"; } @@ -234,6 +239,7 @@ Float StyleSheetLength::asPixels( const Float& parentSize, const Sizef& viewSize ret = Math::roundUp( PixelDensity::dpToPx( mValue ) ); break; case Unit::Em: + case Unit::Ch: // Using Em for Ch is incorrect but not that incorrect, close enough ret = Math::round( mValue * elFontSize ); break; case Unit::Pt: @@ -266,6 +272,10 @@ Float StyleSheetLength::asPixels( const Float& parentSize, const Sizef& viewSize case Unit::Rem: ret = globalFontSize * mValue; break; + case Unit::Dpi: + case Unit::Dpcm: + ret = (int)( mValue * 2.54 ); + break; case Unit::Px: default: ret = mValue; diff --git a/src/eepp/ui/uifiledialog.cpp b/src/eepp/ui/uifiledialog.cpp index 5ae111b17..c2deba159 100644 --- a/src/eepp/ui/uifiledialog.cpp +++ b/src/eepp/ui/uifiledialog.cpp @@ -667,8 +667,12 @@ void UIFileDialog::open() { } void UIFileDialog::onPressEnter( const Event* ) { - if ( FileSystem::isDirectory( mPath->getText() ) || - ( FDLG_DRIVE_PATH == mPath->getText().toUtf8() && !Sys::getLogicalDrives().empty() ) ) { + if ( allowFolderSelect() && FileSystem::isDirectory( mPath->getText() ) ) { + setCurPath( mPath->getText() ); + open(); + } else if ( FileSystem::isDirectory( mPath->getText() ) || + ( FDLG_DRIVE_PATH == mPath->getText().toUtf8() && + !Sys::getLogicalDrives().empty() ) ) { setCurPath( mPath->getText() ); } else if ( !allowFolderSelect() && FileSystem::fileExists( mPath->getText() ) ) { String folderPath( FileSystem::fileRemoveFileName( mPath->getText() ) ); diff --git a/src/eepp/ui/uiimage.cpp b/src/eepp/ui/uiimage.cpp index dfd57f256..1754da04c 100644 --- a/src/eepp/ui/uiimage.cpp +++ b/src/eepp/ui/uiimage.cpp @@ -363,12 +363,7 @@ bool UIImage::applyProperty( const StyleSheetProperty& attribute ) { bool ownIt; if ( uri.getScheme().empty() && !getUISceneNode()->getURI().empty() ) { - uri = getUISceneNode()->getURI(); - std::string newPath = uri.getPath(); - if ( !path.empty() && path[0] != '/' ) - FileSystem::dirAddSlashAtEnd( newPath ); - newPath += path; - uri.setPath( newPath ); + uri = getUISceneNode()->solveRelativePath( uri ); path = uri.toString(); } @@ -379,7 +374,8 @@ bool UIImage::applyProperty( const StyleSheetProperty& attribute ) { setDrawable( createdDrawable, ownIt ); } else { Drawable* res = NULL; - if ( NULL != ( res = DrawableSearcher::searchByName( path ) ) ) + if ( NULL != ( res = DrawableSearcher::searchByName( + path, false, getUISceneNode()->getReferer() ) ) ) setDrawable( res, res->getDrawableType() == Drawable::SPRITE ); } break; diff --git a/src/eepp/ui/uiscenenode.cpp b/src/eepp/ui/uiscenenode.cpp index c3b7784ad..383a03412 100644 --- a/src/eepp/ui/uiscenenode.cpp +++ b/src/eepp/ui/uiscenenode.cpp @@ -1368,7 +1368,7 @@ void UISceneNode::setURI( const URI& uri ) { mURI = uri; } -URI UISceneNode::getURIFromURL( const URI& url ) { +URI UISceneNode::getURIFromURL( const URI& url ) const { URI baseURI( url ); std::string path = baseURI.getPath(); @@ -1396,6 +1396,7 @@ URI UISceneNode::getURIFromURL( const URI& url ) { void UISceneNode::setURIFromURL( const URI& url ) { setURI( getURIFromURL( url ) ); + mReferer = url; } void UISceneNode::openURL( URI uri ) { diff --git a/src/eepp/ui/uiwidgetcreator.cpp b/src/eepp/ui/uiwidgetcreator.cpp index 0999a3b32..fbf87f986 100644 --- a/src/eepp/ui/uiwidgetcreator.cpp +++ b/src/eepp/ui/uiwidgetcreator.cpp @@ -170,6 +170,7 @@ void UIWidgetCreator::createBaseWidgetList() { registeredWidget["article"] = [] { return UIRichText::NewWithTag( "article" ); }; registeredWidget["footer"] = [] { return UIRichText::NewWithTag( "footer" ); }; registeredWidget["main"] = [] { return UIRichText::NewWithTag( "main" ); }; + registeredWidget["section"] = [] { return UIRichText::NewWithTag( "section" ); }; registeredWidget["nav"] = [] { return UIRichText::NewWithTag( "nav" ); }; registeredWidget["center"] = [] { return UIRichText::NewWithTag( "center" ); }; registeredWidget["html"] = [] { return UIRichText::NewWithTag( "html" ); }; diff --git a/src/tests/unit_tests/uihtml_tests.cpp b/src/tests/unit_tests/uihtml_tests.cpp index 8ebb3084e..2917a5eae 100644 --- a/src/tests/unit_tests/uihtml_tests.cpp +++ b/src/tests/unit_tests/uihtml_tests.cpp @@ -49,7 +49,7 @@ UTEST( UIHTMLTable, complexLayout ) { 32, {}, 1, false, true ), ContextSettings( false, 0, 0, GLv_default, true, false ) ); FileSystem::changeWorkingDirectory( Sys::getProcessPath() ); - + FontTrueType* font = FontTrueType::New( "NotoSans-Regular" ); font->loadFromFile( "../assets/fonts/NotoSans-Regular.ttf" ); ASSERT_TRUE( font != nullptr && font->loaded() );