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;
+
+ //