diff --git a/code/.clang-format b/code/.clang-format new file mode 100644 index 000000000..90f4ab553 --- /dev/null +++ b/code/.clang-format @@ -0,0 +1,24 @@ +--- +BasedOnStyle: WebKit +AllowShortFunctionsOnASingleLine: All +BraceWrapping: + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false +BreakBeforeBraces: Custom +BreakConstructorInitializersBeforeComma: 'false' +NamespaceIndentation: None +PointerAlignment: Right +SortIncludes: 'false' +TabWidth: '4' +UseTab: ForIndentation + +... diff --git a/code/.editorconfig b/code/.editorconfig new file mode 100644 index 000000000..e4aef2c53 --- /dev/null +++ b/code/.editorconfig @@ -0,0 +1,23 @@ +; Top-most EditorConfig file +root = true + +; 4-column tab indentation +[*.cpp] +indent_style = tab +indent_size = 4 + +[*.c] +indent_style = tab +indent_size = 4 + +[*.h] +indent_style = tab +indent_size = 4 + +[*.py] +indent_style = tab +indent_size = 4 + +[*.config] +indent_style = space +indent_size = 2 diff --git a/code/CMakeModules/Find3dsMaxSDK.cmake b/code/CMakeModules/Find3dsMaxSDK.cmake index cf49a90d3..cb00df78e 100644 --- a/code/CMakeModules/Find3dsMaxSDK.cmake +++ b/code/CMakeModules/Find3dsMaxSDK.cmake @@ -11,18 +11,56 @@ if(MAXSDK_INCLUDE_DIR) SET(MAXSDK_FIND_QUIETLY TRUE) endif() +set(_pf_x86 "PROGRAMFILES(x86)") + FIND_PATH(MAXSDK_DIR "include/maxversion.h" HINTS "$ENV{MAXSDK_DIR}" PATHS + "$ENV{ADSK_3DSMAX_SDK_2021}/maxsdk" + "$ENV{ADSK_3DSMAX_SDK_2020}/maxsdk" + "$ENV{ADSK_3DSMAX_SDK_2019}/maxsdk" + "$ENV{ADSK_3DSMAX_SDK_2018}/maxsdk" + "$ENV{ADSK_3DSMAX_SDK_2017}/maxsdk" + "$ENV{ADSK_3DSMAX_SDK_2016}/maxsdk" + "$ENV{ADSK_3DSMAX_SDK_2015}/maxsdk" + "$ENV{ADSK_3DSMAX_SDK_2014}/maxsdk" + "$ENV{ADSK_3DSMAX_SDK_2013}/maxsdk" "$ENV{ADSK_3DSMAX_SDK_2012}/maxsdk" "$ENV{3DSMAX_2011_SDK_PATH}/maxsdk" + "$ENV{${_pf_x86}}/Autodesk/3ds Max 2021 SDK/maxsdk" + "$ENV{${_pf_x86}}/Autodesk/3ds Max 2020 SDK/maxsdk" + "$ENV{${_pf_x86}}/Autodesk/3ds Max 2019 SDK/maxsdk" + "$ENV{${_pf_x86}}/Autodesk/3ds Max 2018 SDK/maxsdk" + "$ENV{${_pf_x86}}/Autodesk/3ds Max 2017 SDK/maxsdk" + "$ENV{${_pf_x86}}/Autodesk/3ds Max 2016 SDK/maxsdk" + "$ENV{${_pf_x86}}/Autodesk/3ds Max 2015 SDK/maxsdk" + "$ENV{${_pf_x86}}/Autodesk/3ds Max 2014 SDK/maxsdk" + "$ENV{${_pf_x86}}/Autodesk/3ds Max 2013 SDK/maxsdk" + "$ENV{${_pf_x86}}/Autodesk/3ds Max 2012 SDK/maxsdk" + "$ENV{${_pf_x86}}/Autodesk/3ds Max 2011 SDK/maxsdk" + "$ENV{${_pf_x86}}/Autodesk/3ds Max 2010 SDK/maxsdk" + "$ENV{${_pf_x86}}/Autodesk/3ds Max 2009 SDK/maxsdk" + "$ENV{${_pf_x86}}/Autodesk/3ds Max 2008 SDK/maxsdk" + "$ENV{${_pf_x86}}/Autodesk/3ds Max 9 SDK/maxsdk" + "$ENV{${_pf_x86}}/Autodesk/3dsMax8/maxsdk" + "$ENV{PROGRAMFILES}/Autodesk/3ds Max 2021 SDK/maxsdk" + "$ENV{PROGRAMFILES}/Autodesk/3ds Max 2020 SDK/maxsdk" + "$ENV{PROGRAMFILES}/Autodesk/3ds Max 2019 SDK/maxsdk" + "$ENV{PROGRAMFILES}/Autodesk/3ds Max 2018 SDK/maxsdk" "$ENV{PROGRAMFILES}/Autodesk/3ds Max 2017 SDK/maxsdk" + "$ENV{PROGRAMFILES}/Autodesk/3ds Max 2016 SDK/maxsdk" + "$ENV{PROGRAMFILES}/Autodesk/3ds Max 2015 SDK/maxsdk" + "$ENV{PROGRAMFILES}/Autodesk/3ds Max 2014 SDK/maxsdk" + "$ENV{PROGRAMFILES}/Autodesk/3ds Max 2013 SDK/maxsdk" + "$ENV{PROGRAMFILES}/Autodesk/3ds Max 2012 SDK/maxsdk" + "$ENV{PROGRAMFILES}/Autodesk/3ds Max 2011 SDK/maxsdk" "$ENV{PROGRAMFILES}/Autodesk/3ds Max 2010 SDK/maxsdk" "$ENV{PROGRAMFILES}/Autodesk/3ds Max 2009 SDK/maxsdk" "$ENV{PROGRAMFILES}/Autodesk/3ds Max 2008 SDK/maxsdk" "$ENV{PROGRAMFILES}/Autodesk/3ds Max 9 SDK/maxsdk" + "$ENV{PROGRAMFILES}/Autodesk/3dsMax8/maxsdk" ) FIND_PATH(MAXSDK_INCLUDE_DIR diff --git a/code/CMakeModules/FindMySQL.cmake b/code/CMakeModules/FindMySQL.cmake index 8a92cb0c4..631a96224 100644 --- a/code/CMakeModules/FindMySQL.cmake +++ b/code/CMakeModules/FindMySQL.cmake @@ -16,10 +16,12 @@ IF(MYSQL_INCLUDE_DIR AND MYSQL_LIBRARIES) ELSE() FIND_PATH(MYSQL_INCLUDE_DIR mysql.h - PATH_SUFFIXES mysql + PATH_SUFFIXES mysql mariadb PATHS /usr/include/mysql + /usr/include/mariadb /usr/local/include/mysql + /usr/local/include/mariadb /opt/local/include/mysql5/mysql /opt/local/include/mysql55/mysql /opt/local/include/mysql51/mysql @@ -27,28 +29,29 @@ ELSE() $ENV{SystemDrive}/MySQL/*/include) IF(WIN32 AND MSVC) - FIND_LIBRARY(MYSQL_LIBRARY_RELEASE NAMES libmysql mysqlclient + FIND_LIBRARY(MYSQL_LIBRARY_RELEASE NAMES libmysql mysqlclient libmariadb mariadbclient PATHS $ENV{ProgramFiles}/MySQL/*/lib/opt $ENV{SystemDrive}/MySQL/*/lib/opt) - - FIND_LIBRARY(MYSQL_LIBRARY_DEBUG NAMES libmysqld mysqlclientd + FIND_LIBRARY(MYSQL_LIBRARY_DEBUG NAMES libmysqld mysqlclientd libmariadb mariadbclient PATHS $ENV{ProgramFiles}/MySQL/*/lib/opt $ENV{SystemDrive}/MySQL/*/lib/opt) ELSE() - FIND_LIBRARY(MYSQL_LIBRARY_RELEASE NAMES mysqlclient + FIND_LIBRARY(MYSQL_LIBRARY_RELEASE NAMES mysqlclient mariadbclient PATHS /usr/lib /usr/local/lib + /usr/lib/mariadb /usr/lib/mysql /usr/local/lib/mysql + /usr/local/lib/mariadb /opt/local/lib/mysql5/mysql /opt/local/lib/mysql55/mysql /opt/local/lib/mysql51/mysql ) - FIND_LIBRARY(MYSQL_LIBRARY_DEBUG NAMES mysqlclientd + FIND_LIBRARY(MYSQL_LIBRARY_DEBUG NAMES mysqlclientd mariadbclientd PATHS /usr/lib /usr/local/lib @@ -80,6 +83,10 @@ ELSE() IF(MYSQL_INCLUDE_DIR AND MYSQL_LIBRARIES) SET(MYSQL_FOUND TRUE) MESSAGE(STATUS "Found MySQL: ${MYSQL_INCLUDE_DIR}, ${MYSQL_LIBRARIES}") + IF (MYSQL_LIBRARIES MATCHES "libmariadb" OR MYSQL_LIBRARIES MATCHES "mariadbclient") + SET(MARIADB_FOUND TRUE) + MESSAGE(STATUS "Found MariaDB.") + ENDIF() ELSE() SET(MYSQL_FOUND FALSE) MESSAGE(STATUS "MySQL not found.") diff --git a/code/CMakeModules/nel.cmake b/code/CMakeModules/nel.cmake index b216eb1e4..bd70dd2ff 100644 --- a/code/CMakeModules/nel.cmake +++ b/code/CMakeModules/nel.cmake @@ -568,6 +568,11 @@ MACRO(NL_SETUP_BUILD) ADD_PLATFORM_FLAGS("-DENABLE_LOGS") ENDIF() + SET(CUSTOM_FLAGS "" CACHE STRING "Custom compile flags (useful for /MPn)") + IF(NOT ${CUSTOM_FLAGS} STREQUAL "") + ADD_PLATFORM_FLAGS(${CUSTOM_FLAGS}) + ENDIF() + IF(MSVC) # Ignore default include paths ADD_PLATFORM_FLAGS("/X") diff --git a/code/nel/include/nel/gui/css_parser.h b/code/nel/include/nel/gui/css_parser.h new file mode 100644 index 000000000..cfaf03caa --- /dev/null +++ b/code/nel/include/nel/gui/css_parser.h @@ -0,0 +1,150 @@ +// Ryzom - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef CL_CSS_PARSER_H +#define CL_CSS_PARSER_H + +#include "nel/misc/types_nl.h" +#include "nel/gui/css_style.h" +#include "nel/gui/css_selector.h" + +namespace NLGUI +{ + /** + * \brief CSS style parsing + * \date 2019-03-15 10:50 GMT + * \author Meelis Mägi (Nimetu) + */ + class CCssParser { + public: + // parse style declaration, eg "color: red; font-size: 10px;" + static TStyle parseDecls(const std::string &styleString); + + // parse css stylesheet + void parseStylesheet(const std::string &cssString, std::vector &rules); + + private: + // stylesheet currently parsed + ucstring _Style; + // keep track of current position in _Style + size_t _Position; + + std::vector _Rules; + + private: + // @media ( .. ) { .. } + void readAtRule(); + + // a#id.class[attr=val] { .. } + void readRule(); + + // move past whitespace + void skipWhitespace(); + + // skip valid IDENT + bool skipIdentifier(); + + // skip over {}, (), or [] block + void skipBlock(); + + // skip over string quoted with ' or " + void skipString(); + + // backslash escape + void escape(); + + // normalize newline chars and remove comments + void preprocess(); + + // parse selectors + combinators + std::vector parse_selector(const ucstring &sel, std::string &pseudoElement) const; + + // parse selector and style + void parseRule(const ucstring &selectorString, const ucstring &styleString); + + inline bool is_eof() const + { + return _Position >= _Style.size(); + } + + inline bool is_whitespace(ucchar ch) const + { + return (ch == (ucchar)' ' || ch == (ucchar)'\t' || ch == (ucchar)'\n'); + } + + inline bool is_hex(ucchar ch) const + { + return ((ch >= (ucchar)'0' && ch <= (ucchar)'9') || + (ch >= (ucchar)'a' && ch <= (ucchar)'f') || + (ch >= (ucchar)'A' && ch <= (ucchar)'F')); + } + + inline bool maybe_escape() const + { + // escaping newline (\n) only allowed inside strings + return (_Style.size() - _Position) >= 1 && _Style[_Position] == (ucchar)'\\' && _Style[_Position+1] != '\n'; + } + + inline bool is_quote(ucchar ch) const + { + return ch== (ucchar)'"' || ch == (ucchar)'\''; + } + + inline bool is_block_open(ucchar ch) const + { + return ch == (ucchar)'{' || ch == (ucchar)'[' || ch == (ucchar)'('; + } + + inline bool is_block_close(ucchar ch, ucchar open) const + { + return ((open == '{' && ch == (ucchar)'}') || + (open == '[' && ch == (ucchar)']') || + (open == '(' && ch == (ucchar)')')); + } + + inline bool is_comment_open() const + { + if (_Position+1 > _Style.size()) + return false; + + return _Style[_Position] == (ucchar)'/' && _Style[_Position+1] == (ucchar)'*'; + } + + inline bool is_nonascii(ucchar ch) const + { + return ch >= 0x80 /*&& ch <= 255*/; + } + + inline bool is_alpha(ucchar ch) const + { + return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); + } + + inline bool is_digit(ucchar ch) const + { + return ch >= '0' && ch <= '9'; + } + + inline bool is_nmchar(ucchar ch) const + { + // checking escape here does not check if next char is '\n' or not + return ch == '_' || ch == '-' || is_alpha(ch) || is_digit(ch) || is_nonascii(ch) || ch == '\\'/*is_escape(ch)*/; + } + }; +}//namespace + +#endif // CL_CSS_PARSER_H + diff --git a/code/nel/include/nel/gui/css_selector.h b/code/nel/include/nel/gui/css_selector.h new file mode 100644 index 000000000..84b039089 --- /dev/null +++ b/code/nel/include/nel/gui/css_selector.h @@ -0,0 +1,107 @@ +// Ryzom - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef CL_CSS_SELECTOR_H +#define CL_CSS_SELECTOR_H + +#include "nel/misc/types_nl.h" + +namespace NLGUI +{ + class CHtmlElement; + + /** + * \brief CSS selector + * \date 2019-03-15 10:50 GMT + * \author Meelis Mägi (Nimetu) + */ + class CCssSelector + { + public: + enum ECombinator { + NONE = 0, + GENERAL_CHILD, + ADJACENT_SIBLING, + GENERAL_SIBLING, + CHILD_OF + }; + + struct SAttribute { + std::string key; + std::string value; + char op; // =, ~, |, ^, $, * + SAttribute(const std::string &k, const std::string &v, char o) + :key(k),value(v),op(o) + {} + }; + + std::string Element; + std::string Id; + std::vector Class; + std::vector Attr; + std::vector PseudoClass; + + // css combinator or \0 missing (first element) + char Combinator; + + public: + // TODO: rewrite for ECombinator enum + CCssSelector(std::string elm="", std::string id="", std::string cls="", char comb = '\0'); + + // helper for sorting + uint32 specificity() const; + + // set classes used, eg 'class1 class2' + void setClass(const std::string &cls); + + // add attribute to selector + // ' ' op means 'key exists, ignore value' + void addAttribute(const std::string &key, const std::string &val = "", char op = ' '); + + // add pseudo class to selector, eg 'first-child' + void addPseudoClass(const std::string &key); + + // true if no rules have been defined + bool empty() const + { + return Element.empty() && Id.empty() && Class.empty() && Attr.empty() && PseudoClass.empty(); + } + + // Test current selector to html DOM element + // NOTE: Does not check combinator + bool match(const CHtmlElement &elm) const; + + private: + bool matchClass(const CHtmlElement &elm) const; + bool matchAttributes(const CHtmlElement &elm) const; + bool matchPseudoClass(const CHtmlElement &elm) const; + + // match An+B rule to child index (1 based) + bool matchNth(sint childNr, sint a, sint b) const; + + // parse nth-child string to 'a' and 'b' components + // :nth-child(odd) + // :nth-child(even) + // :nth-child(An+B) + // :nth-child(-An+b) + void parseNth(const std::string &pseudo, sint &a, sint &b) const; + + }; + +}//namespace + +#endif // CL_CSS_SELECTOR_H + diff --git a/code/nel/include/nel/gui/css_style.h b/code/nel/include/nel/gui/css_style.h new file mode 100644 index 000000000..74fcf240d --- /dev/null +++ b/code/nel/include/nel/gui/css_style.h @@ -0,0 +1,227 @@ +// Ryzom - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef CL_CSS_STYLE_H +#define CL_CSS_STYLE_H + +#include "nel/misc/types_nl.h" +#include "nel/misc/rgba.h" +#include "nel/gui/css_selector.h" + +namespace NLGUI +{ + class CHtmlElement; + + typedef std::map TStyle; + + /** + * \brief CSS style rules + * \date 2019-03-15 10:50 GMT + * \author Meelis Mägi (Nimetu) + */ + class CStyleParams + { + public: + struct STextShadow + { + public: + STextShadow(bool enabled = false, bool outline = false, sint32 x=1, sint32 y=1, NLMISC::CRGBA color=NLMISC::CRGBA::Black) + : Enabled(enabled), Outline(outline), X(x), Y(y), Color(color) + { } + + bool Enabled; + bool Outline; + sint32 X; + sint32 Y; + NLMISC::CRGBA Color; + }; + public: + CStyleParams () : FontFamily(""), TextColor(255,255,255,255), TextShadow() + { + FontSize=10; + FontWeight=400; + FontOblique=false; + Underlined=false; + StrikeThrough=false; + GlobalColor=false; + Width=-1; + Height=-1; + MaxWidth=-1; + MaxHeight=-1; + BorderWidth=1; + BackgroundColor=NLMISC::CRGBA::Black; + BackgroundColorOver=NLMISC::CRGBA::Black; + } + + bool hasStyle(const std::string &key) const + { + return StyleRules.find(key) != StyleRules.end(); + } + + std::string getStyle(const std::string &key) const + { + TStyle::const_iterator it = StyleRules.find(key); + return (it != StyleRules.end() ? it->second : ""); + } + + public: + uint FontSize; + uint FontWeight; + bool FontOblique; + std::string FontFamily; + NLMISC::CRGBA TextColor; + STextShadow TextShadow; + bool GlobalColor; + bool Underlined; + bool StrikeThrough; + sint32 Width; + sint32 Height; + sint32 MaxWidth; + sint32 MaxHeight; + sint32 BorderWidth; + NLMISC::CRGBA BackgroundColor; + NLMISC::CRGBA BackgroundColorOver; + + std::string WhiteSpace; + std::string TextAlign; + std::string VerticalAlign; + + TStyle StyleRules; + }; + + class CCssStyle { + public: + struct SStyleRule { + std::vector Selector; + TStyle Properties; + + // pseudo element like ':before' + std::string PseudoElement; + + // returns selector specificity + uint specificity() const; + }; + + // 'browser' style, overwriten with '' + CStyleParams Root; + + // current element style + CStyleParams Current; + + // known style rules sorted by specificity + std::vector _StyleRules; + + private: + std::vector _StyleStack; + + // test if str is one of "thin/medium/thick" and return its pixel value + bool scanCssLength(const std::string& str, uint32 &px) const; + + // read style attribute + void getStyleParams(const std::string &styleString, CStyleParams &style, const CStyleParams ¤t) const; + void getStyleParams(const TStyle &styleRules, CStyleParams &style, const CStyleParams ¤t) const; + + // extract from styleRules into style.StyleRules (expand shorthand, normalize, calculate current font-size) + void normalize(const TStyle &styleRules, CStyleParams &style, const CStyleParams ¤t) const; + + // apply style.StyleRyles + void apply(CStyleParams &style, const CStyleParams ¤t) const; + + // merge src into dest by overwriting key in dest + void merge(TStyle &dst, const TStyle &src) const; + + // match selector to dom path + bool match(const std::vector &selector, const CHtmlElement &elm) const; + + // parse 'background' into 'background-color', 'background-image', etc + void parseBackgroundShorthand(const std::string &value, CStyleParams &style) const; + + public: + void reset(); + + // parse tag or css file content + void parseStylesheet(const std::string &styleString); + + // set element style from matching css rules + void getStyleFor(CHtmlElement &elm) const; + + inline uint getFontSizeSmaller() const + { + if (Current.FontSize < 5) + return 3; + return Current.FontSize-2; + } + + sint styleStackIndex = 0; + + inline void pushStyle() + { + styleStackIndex++; + _StyleStack.push_back(Current); + + Current.Width=-1; + Current.Height=-1; + Current.MaxWidth=-1; + Current.MaxHeight=-1; + Current.BorderWidth=1; + + Current.StyleRules.clear(); + } + + inline void popStyle() + { + styleStackIndex--; + if (_StyleStack.empty()) + { + Current = Root; + } + else + { + Current = _StyleStack.back(); + _StyleStack.pop_back(); + } + } + + // apply style to this.Root + void applyRootStyle(const std::string &styleString); + void applyRootStyle(const TStyle &styleRules); + + // apply style to this.Current + void applyStyle(const std::string &styleString); + void applyStyle(const TStyle &styleRules); + + void applyCssMinMax(sint32 &width, sint32 &height, sint32 minw=0, sint32 minh=0, sint32 maxw=0, sint32 maxh=0) const; + + // check if current style property matches value + bool checkStyle(const std::string &key, const std::string &val) const + { + return Current.hasStyle(key) && Current.getStyle(key) == val; + } + + bool hasStyle(const std::string &key) const + { + return Current.hasStyle(key); + } + + std::string getStyle(const std::string &key) const + { + return Current.getStyle(key); + } + }; +}//namespace + +#endif // CL_CSS_STYLE_H + diff --git a/code/nel/include/nel/gui/group_html.h b/code/nel/include/nel/gui/group_html.h index 55daa3c52..fc29c840d 100644 --- a/code/nel/include/nel/gui/group_html.h +++ b/code/nel/include/nel/gui/group_html.h @@ -23,13 +23,12 @@ #include "nel/gui/group_tree.h" #include "nel/gui/ctrl_button.h" #include "nel/gui/group_table.h" -#include "nel/gui/libwww_types.h" +#include "nel/gui/html_element.h" +#include "nel/gui/css_style.h" // forward declaration typedef void CURLM; -typedef std::map TStyle; - namespace NLGUI { class CCtrlButton; @@ -69,67 +68,15 @@ namespace NLGUI /// Maximum concurrent MultiCurl connections per CGroupHTML instance sint32 curlMaxConnections; - SWebOptions(): curlMaxConnections(2) + SWebOptions(): curlMaxConnections(5) { } }; static SWebOptions options; - // text-shadow - struct STextShadow - { - public: - STextShadow(bool enabled = false, bool outline = false, sint32 x=1, sint32 y=1, NLMISC::CRGBA color=NLMISC::CRGBA::Black) - : Enabled(enabled), Outline(outline), X(x), Y(y), Color(color) - { } - - bool Enabled; - bool Outline; - sint32 X; - sint32 Y; - NLMISC::CRGBA Color; - }; - - class CStyleParams - { - public: - CStyleParams () : FontFamily(""), TextColor(255,255,255,255), TextShadow() - { - FontSize=10; - FontWeight=400; - FontOblique=false; - Underlined=false; - StrikeThrough=false; - GlobalColor=false; - Width=-1; - Height=-1; - MaxWidth=-1; - MaxHeight=-1; - BorderWidth=1; - BackgroundColor=NLMISC::CRGBA::Black; - BackgroundColorOver=NLMISC::CRGBA::Black; - } - uint FontSize; - uint FontWeight; - bool FontOblique; - std::string FontFamily; - NLMISC::CRGBA TextColor; - STextShadow TextShadow; - bool GlobalColor; - bool Underlined; - bool StrikeThrough; - sint32 Width; - sint32 Height; - sint32 MaxWidth; - sint32 MaxHeight; - sint32 BorderWidth; - NLMISC::CRGBA BackgroundColor; - NLMISC::CRGBA BackgroundColorOver; - }; - // ImageDownload system - enum TDataType {ImgType= 0, BnpType}; + enum TDataType {ImgType= 0, BnpType, StylesheetType}; enum TImageType {NormalImage=0, OverImage}; // Constructor @@ -150,8 +97,11 @@ namespace NLGUI // Browse virtual void browse (const char *url); + // load css from local file and insert into active stylesheet collection + void parseStylesheetFile(const std::string &fname); + // parse html string using libxml2 parser - virtual bool parseHtml(std::string htmlString); + bool parseHtml(const std::string &htmlString); // Refresh void refresh(); @@ -162,13 +112,8 @@ namespace NLGUI // Browse error void browseError (const char *msg); - // stop browse - void stopBrowse (); - bool isBrowsing(); - void clean() { stopBrowse(); updateRefreshButton(); removeContent(); } - // Update coords void updateCoords(); @@ -287,8 +232,6 @@ namespace NLGUI int luaInsertText(CLuaState &ls); int luaAddString(CLuaState &ls); int luaAddImage(CLuaState &ls); - int luaBeginElement(CLuaState &ls); - int luaEndElement(CLuaState &ls); int luaShowDiv(CLuaState &ls); int luaParseHtml(CLuaState &ls); int luaRenderHtml(CLuaState &ls); @@ -302,8 +245,6 @@ namespace NLGUI REFLECT_LUA_METHOD("insertText", luaInsertText) REFLECT_LUA_METHOD("addString", luaAddString) REFLECT_LUA_METHOD("addImage", luaAddImage) - REFLECT_LUA_METHOD("beginElement", luaBeginElement) - REFLECT_LUA_METHOD("endElement", luaEndElement) REFLECT_LUA_METHOD("showDiv", luaShowDiv) REFLECT_LUA_METHOD("parseHtml", luaParseHtml) REFLECT_LUA_METHOD("renderHtml", luaRenderHtml) @@ -316,26 +257,20 @@ namespace NLGUI // \name callback from libwww - // Begin of the parsing of a HTML document + // Begin of the rendering of a HTML document virtual void beginBuild (); - // End of the parsing of a HTML document + // End of the rendering of a HTML document virtual void endBuild (); // A new text block has been parsed virtual void addText (const char * buf, int len); // A new begin HTML element has been parsed ( for exemple) - virtual void beginElement (uint element_number, const std::vector &present, const std::vector &value); + virtual void beginElement(CHtmlElement &elm); // A new end HTML element has been parsed ( for exemple) - virtual void endElement (uint element_number); - - // A new begin unparsed element has been found - virtual void beginUnparsedElement(const char *buffer, int length); - - // A new end unparsed element has been found - virtual void endUnparsedElement(const char *buffer, int length); + virtual void endElement(CHtmlElement &elm); // Add GET params to the url virtual void addHTTPGetParams (std::string &url, bool trustedDomain); @@ -343,16 +278,12 @@ namespace NLGUI // Add POST params to the libwww list virtual void addHTTPPostParams (SFormFields &formfields, bool trustedDomain); - // the current request is terminated - virtual void requestTerminated(); - - // libxml2 html parser functions - void htmlElement(xmlNode *node, int element_number); - void htmlWalkDOM(xmlNode *a_node); - // Get Home URL virtual std::string home(); + // parse dom node and all child nodes recursively + void renderDOM(CHtmlElement &elm); + // Clear style stack and restore default style void resetCssStyle(); @@ -383,7 +314,7 @@ namespace NLGUI void addString(const ucstring &str); // Add an image in the current paragraph - void addImage(const std::string &id, const char *image, bool reloadImg=false, const CStyleParams &style = CStyleParams()); + void addImage(const std::string &id, const std::string &img, bool reloadImg=false, const CStyleParams &style = CStyleParams()); // Add a text area in the current paragraph CInterfaceGroup *addTextArea (const std::string &templateName, const char *name, uint rows, uint cols, bool multiLine, const ucstring &content, uint maxlength); @@ -422,6 +353,14 @@ namespace NLGUI // Current URL std::string _DocumentUrl; std::string _DocumentDomain; + std::string _DocumentHtml; // not updated, only set by first render + // If true, then render _DocumentHtml on next update (replaces content) + bool _RenderNextTime; + // true if renderer is waiting for css files to finish downloading (link rel=stylesheet) + bool _WaitingForStylesheet; + // list of css file urls that are queued up for download + std::vector _StylesheetQueue; + // Valid base href was found bool _IgnoreBaseUrlTag; // Fragment from loading url @@ -454,7 +393,6 @@ namespace NLGUI // Browsing.. bool _Browsing; - bool _Connecting; double _TimeoutValue; // the timeout in seconds double _ConnectingTimeout; sint _RedirectsRemaining; @@ -539,33 +477,13 @@ namespace NLGUI // IL mode bool _LI; - // Current active style - CStyleParams _Style; - // Default style - CStyleParams _StyleDefault; - // Nested style stack - std::vector _StyleParams; - inline void pushStyle() - { - _StyleParams.push_back(_Style); - } - inline void popStyle() - { - if (_StyleParams.empty()) - _Style = _StyleDefault; - else - { - _Style = _StyleParams.back(); - _StyleParams.pop_back(); - } - } - - inline uint getFontSizeSmaller() const - { - if (_Style.FontSize < 5) - return 3; - return _Style.FontSize-2; - } + // Keep track of current element style + CCssStyle _Style; + CHtmlElement _HtmlDOM; + CHtmlElement *_CurrentHTMLElement; + // Backup of CurrentHTMLElement->nextSibling before ::beginElement() is called + // for luaParseHtml() to insert nodes into right place in right order + CHtmlElement *_CurrentHTMLNextSibling; // Current link std::vector _Link; @@ -629,14 +547,6 @@ namespace NLGUI return _TR.back(); } - std::vector _TextShadow; - inline STextShadow getTextShadow() const - { - if (_TextShadow.empty()) - return STextShadow(); - return _TextShadow.back(); - } - // Forms class CForm { @@ -798,10 +708,6 @@ namespace NLGUI typedef std::map > TGroupHtmlByUIDMap; static TGroupHtmlByUIDMap _GroupHtmlByUID; - // read style attribute - void getStyleParams(const std::string &styleString, CStyleParams &style, const CStyleParams ¤t); - void applyCssMinMax(sint32 &width, sint32 &height, sint32 minw=0, sint32 minh=0, sint32 maxw=0, sint32 maxh=0); - // load and render local html file (from bnp for example) void doBrowseLocalFile(const std::string &filename); @@ -815,6 +721,11 @@ namespace NLGUI void buildHTTPPostParams (SFormFields &formfields); private: + friend class CHtmlParser; + + // move src->Children into CurrentHtmlElement.parent.children element + void spliceFragment(std::list::iterator src); + // decode all HTML entities static ucstring decodeHTMLEntities(const ucstring &str); @@ -834,10 +745,11 @@ namespace NLGUI { public: CDataDownload(const std::string &u, const std::string &d, TDataType t, CViewBase *i, const std::string &s, const std::string &m, const CStyleParams &style = CStyleParams(), const TImageType imagetype = NormalImage) - : data(NULL), fp(NULL), url(u), dest(d), type(t), luaScript(s), md5sum(m), redirects(0) + : data(NULL), fp(NULL), url(u), dest(d), type(t), luaScript(s), md5sum(m), redirects(0), ConnectionTimeout(60) { if (t == ImgType) imgs.push_back(CDataImageDownload(i, style, imagetype)); } + ~CDataDownload(); public: CCurlWWWData *data; @@ -849,13 +761,16 @@ namespace NLGUI uint32 redirects; FILE *fp; std::vector imgs; + uint32 ConnectionTimeout; }; - std::vector Curls; + std::list Curls; CURLM *MultiCurl; int RunningCurls; bool startCurlDownload(CDataDownload &download); + void finishCurlDownload(const CDataDownload &download); + void pumpCurlQueue(); void initImageDownload(); void checkImageDownload(); @@ -874,11 +789,103 @@ namespace NLGUI bool addBnpDownload(std::string url, const std::string &action, const std::string &script, const std::string &md5sum); std::string localBnpName(const std::string &url); + // add css file from to download queue + void addStylesheetDownload(std::vector links); + + // stop all curl downalods (html and data) void releaseDownloads(); void checkDownloads(); + // _CurlWWW download finished + void htmlDownloadFinished(bool success, const std::string &error); + // images, stylesheets, etc finished downloading + void dataDownloadFinished(bool success, const std::string &error, CDataDownload &data); + // HtmlType download finished void htmlDownloadFinished(const std::string &content, const std::string &type, long code); + + // stylesheet finished downloading. if local file does not exist, then it failed (404) + void cssDownloadFinished(const std::string &url, const std::string &local); + + // read common table/tr/td parameters and push them to _CellParams + void getCellsParameters(const CHtmlElement &elm, bool inherit); + + // render _HtmlDOM + void renderDocument(); + + // :before, :after rendering + void renderPseudoElement(const std::string &pseudo, const CHtmlElement &elm); + + // apply background from current style (for html, body) + void applyBackground(const CHtmlElement &elm); + + // HTML elements + void htmlA(const CHtmlElement &elm); + void htmlAend(const CHtmlElement &elm); + void htmlBASE(const CHtmlElement &elm); + void htmlBODY(const CHtmlElement &elm); + void htmlBR(const CHtmlElement &elm); + void htmlDD(const CHtmlElement &elm); + void htmlDDend(const CHtmlElement &elm); + //void htmlDEL(const CHtmlElement &elm); + void htmlDIV(const CHtmlElement &elm); + void htmlDIVend(const CHtmlElement &elm); + void htmlDL(const CHtmlElement &elm); + void htmlDLend(const CHtmlElement &elm); + void htmlDT(const CHtmlElement &elm); + void htmlDTend(const CHtmlElement &elm); + //void htmlEM(const CHtmlElement &elm); + void htmlFONT(const CHtmlElement &elm); + void htmlFORM(const CHtmlElement &elm); + void htmlH(const CHtmlElement &elm); + void htmlHend(const CHtmlElement &elm); + void htmlHEAD(const CHtmlElement &elm); + void htmlHEADend(const CHtmlElement &elm); + void htmlHR(const CHtmlElement &elm); + void htmlHTML(const CHtmlElement &elm); + void htmlI(const CHtmlElement &elm); + void htmlIend(const CHtmlElement &elm); + void htmlIMG(const CHtmlElement &elm); + void htmlINPUT(const CHtmlElement &elm); + void htmlLI(const CHtmlElement &elm); + void htmlLIend(const CHtmlElement &elm); + void htmlLUA(const CHtmlElement &elm); + void htmlLUAend(const CHtmlElement &elm); + void htmlMETA(const CHtmlElement &elm); + void htmlOBJECT(const CHtmlElement &elm); + void htmlOBJECTend(const CHtmlElement &elm); + void htmlOL(const CHtmlElement &elm); + void htmlOLend(const CHtmlElement &elm); + void htmlOPTION(const CHtmlElement &elm); + void htmlOPTIONend(const CHtmlElement &elm); + void htmlP(const CHtmlElement &elm); + void htmlPend(const CHtmlElement &elm); + void htmlPRE(const CHtmlElement &elm); + void htmlPREend(const CHtmlElement &elm); + void htmlSCRIPT(const CHtmlElement &elm); + void htmlSCRIPTend(const CHtmlElement &elm); + void htmlSELECT(const CHtmlElement &elm); + void htmlSELECTend(const CHtmlElement &elm); + //void htmlSMALL(const CHtmlElement &elm); + //void htmlSPAN(const CHtmlElement &elm); + //void htmlSTRONG(const CHtmlElement &elm); + void htmlSTYLE(const CHtmlElement &elm); + void htmlSTYLEend(const CHtmlElement &elm); + void htmlTABLE(const CHtmlElement &elm); + void htmlTABLEend(const CHtmlElement &elm); + void htmlTD(const CHtmlElement &elm); + void htmlTDend(const CHtmlElement &elm); + void htmlTEXTAREA(const CHtmlElement &elm); + void htmlTEXTAREAend(const CHtmlElement &elm); + void htmlTH(const CHtmlElement &elm); + void htmlTHend(const CHtmlElement &elm); + void htmlTITLE(const CHtmlElement &elm); + void htmlTITLEend(const CHtmlElement &elm); + void htmlTR(const CHtmlElement &elm); + void htmlTRend(const CHtmlElement &elm); + //void htmlU(const CHtmlElement &elm); + void htmlUL(const CHtmlElement &elm); + void htmlULend(const CHtmlElement &elm); }; // adapter group that store y offset for inputs inside an html form diff --git a/code/nel/include/nel/gui/html_element.h b/code/nel/include/nel/gui/html_element.h new file mode 100644 index 000000000..bac681c1c --- /dev/null +++ b/code/nel/include/nel/gui/html_element.h @@ -0,0 +1,86 @@ +// Ryzom - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef CL_HTML_ELEMENT_H +#define CL_HTML_ELEMENT_H + +#include "nel/misc/types_nl.h" +#include "nel/gui/css_style.h" + +namespace NLGUI +{ + /** + * \brief HTML element + * \date 2019-04-25 18:23 GMT + * \author Meelis Mägi (Nimetu) + */ + class CHtmlElement + { + public: + enum ENodeType { + NONE = 0, + ELEMENT_NODE = 1, + TEXT_NODE = 3, + }; + + uint ID; // libwww element enum + ENodeType Type; + std::string Value; // text node value or element node name + std::map Attributes; + std::list Children; + + // class names for css matching + std::set ClassNames; + + // defined style and :before/:after pseudo elements + TStyle Style; + TStyle StyleBefore; + TStyle StyleAfter; + + // hierarchy + CHtmlElement *parent; + CHtmlElement *previousSibling; + CHtmlElement *nextSibling; + + // n'th ELEMENT_NODE in parent.Children, for :nth-child() rules + uint childIndex; + + CHtmlElement(ENodeType type = NONE, std::string value = ""); + + // returns true if rhs is same pointer + friend bool operator==(const CHtmlElement &lhs, const CHtmlElement &rhs) + { + return &lhs == &rhs; + } + + bool hasAttribute(const std::string &key) const; + + bool hasNonEmptyAttribute(const std::string &key) const; + + std::string getAttribute(const std::string &key) const; + + bool hasClass(const std::string &key) const; + + // update Children index/parent/next/prevSibling pointers + void reindexChilds(); + + // debug + std::string toString(bool tree = false, uint depth = 0) const; + }; +} + +#endif + diff --git a/code/nel/include/nel/gui/html_parser.h b/code/nel/include/nel/gui/html_parser.h new file mode 100644 index 000000000..760640234 --- /dev/null +++ b/code/nel/include/nel/gui/html_parser.h @@ -0,0 +1,52 @@ +// Ryzom - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef CL_HTML_PARSER_H +#define CL_HTML_PARSER_H + +#include "nel/misc/types_nl.h" + +namespace NLGUI +{ + class CHtmlElement; + + /** + * \brief HTML parsing + * \date 2019-03-15 10:50 GMT + * \author Meelis Mägi (Nimetu) + */ + class CHtmlParser + { + public: + bool parseHtml(std::string htmlString) const; + + // parse html string into DOM, extract + bool useStyle = true; + if (elm.hasAttribute("media")) + { + std::string media = trim(toLower(elm.Attributes["media"])); + useStyle = media.empty() || media.find("all") != std::string::npos || media.find("screen") != std::string::npos; + + //