From d67a9ccdb538299bc082d63b9043772f813607ae Mon Sep 17 00:00:00 2001 From: Nimetu Date: Thu, 25 Apr 2019 08:28:45 +0300 Subject: [PATCH 01/75] Backed out changeset: ce73fd40aa54 --HG-- branch : develop --- code/nel/src/misc/file.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/nel/src/misc/file.cpp b/code/nel/src/misc/file.cpp index 54ffdfbc6..414a10e5a 100644 --- a/code/nel/src/misc/file.cpp +++ b/code/nel/src/misc/file.cpp @@ -185,7 +185,7 @@ bool CIFile::open(const std::string &path, bool text) // Bigfile or xml pack access requested ? string::size_type pos; - if (!CFile::fileExists(path) && (pos = path.find('@')) != string::npos) + if ((pos = path.find('@')) != string::npos) { // check for a double @ to identify XML pack file if (pos+1 < path.size() && path[pos+1] == '@') From f065b7f7479aa2da1691a8290bfd0e9fd2d67c71 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Thu, 25 Apr 2019 08:38:23 +0300 Subject: [PATCH 02/75] Fixed: Opening local file with @ char in filename --HG-- branch : develop --- code/nel/src/misc/file.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/nel/src/misc/file.cpp b/code/nel/src/misc/file.cpp index 414a10e5a..7eae0f6a5 100644 --- a/code/nel/src/misc/file.cpp +++ b/code/nel/src/misc/file.cpp @@ -237,7 +237,9 @@ bool CIFile::open(const std::string &path, bool text) } } } - else + + // not in bnp, but may have '@' in the name + if (_F == NULL) { _IsInBigFile = false; _IsInXMLPackFile = false; From 82f084982a45947cd203b628833f0841ba930092 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Mon, 29 Apr 2019 14:10:19 +0300 Subject: [PATCH 03/75] Fixed: Reusing CIFile to load from bnp and from regular files. --HG-- branch : develop --- code/nel/src/misc/file.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/code/nel/src/misc/file.cpp b/code/nel/src/misc/file.cpp index 7eae0f6a5..63b27e768 100644 --- a/code/nel/src/misc/file.cpp +++ b/code/nel/src/misc/file.cpp @@ -157,6 +157,14 @@ bool CIFile::open(const std::string &path, bool text) close(); + if ((_IsInBigFile || _IsInXMLPackFile) && path.find('@') == string::npos) + { + // CIFile can be reused to load file from bnp and from regular files. + // Last open happened to be inside bnp and close() may not set _F to NULL. + // Opening regular file will fail as _F points to bnp file. + _F = NULL; + } + // can't open empty filename if(path.empty ()) return false; From 7f41881be7b05bddc2a050c860fd845c3831de9e Mon Sep 17 00:00:00 2001 From: Nimetu Date: Mon, 29 Apr 2019 15:03:32 +0300 Subject: [PATCH 04/75] Changed: Split http parsing from CGroupHTML --HG-- branch : develop --- code/nel/include/nel/gui/group_html.h | 8 ++- code/nel/include/nel/gui/html_parser.h | 52 +++++++++++++++++++ code/nel/src/gui/group_html.cpp | 26 ++++++++++ ...{group_html_parser.cpp => html_parser.cpp} | 37 +++++-------- 4 files changed, 94 insertions(+), 29 deletions(-) create mode 100644 code/nel/include/nel/gui/html_parser.h rename code/nel/src/gui/{group_html_parser.cpp => html_parser.cpp} (89%) diff --git a/code/nel/include/nel/gui/group_html.h b/code/nel/include/nel/gui/group_html.h index 55daa3c52..b21841f8c 100644 --- a/code/nel/include/nel/gui/group_html.h +++ b/code/nel/include/nel/gui/group_html.h @@ -151,7 +151,7 @@ namespace NLGUI virtual void browse (const char *url); // parse html string using libxml2 parser - virtual bool parseHtml(std::string htmlString); + bool parseHtml(const std::string &htmlString); // Refresh void refresh(); @@ -346,10 +346,6 @@ namespace NLGUI // 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(); @@ -815,6 +811,8 @@ namespace NLGUI void buildHTTPPostParams (SFormFields &formfields); private: + friend class CHtmlParser; + // decode all HTML entities static ucstring decodeHTMLEntities(const ucstring &str); 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..132c4ac88 --- /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 CGroupHTML; + + /** + * \brief HTML parsing + * \date 2019-03-15 10:50 GMT + * \author Meelis Mägi (Nimetu) + */ + class CHtmlParser + { + public: + CHtmlParser(CGroupHTML *group) : _GroupHtml(group) + {} + + bool parseHtml(std::string htmlString); + + private: + // libxml2 html parser functions + void htmlElement(xmlNode *node, int element_number); + void parseNode(xmlNode *a_node); + + private: + + CGroupHTML *_GroupHtml; + }; + +} + +#endif + diff --git a/code/nel/src/gui/group_html.cpp b/code/nel/src/gui/group_html.cpp index 0bdebf865..36d0eab7f 100644 --- a/code/nel/src/gui/group_html.cpp +++ b/code/nel/src/gui/group_html.cpp @@ -48,6 +48,7 @@ #include "nel/gui/http_cache.h" #include "nel/gui/http_hsts.h" #include "nel/gui/curl_certificates.h" +#include "nel/gui/html_parser.h" #include @@ -6049,6 +6050,19 @@ namespace NLGUI return true; } + // *************************************************************************** + int CGroupHTML::luaParseHtml(CLuaState &ls) + { + const char *funcName = "parseHtml"; + CLuaIHM::checkArgCount(ls, funcName, 1); + CLuaIHM::checkArgType(ls, funcName, 1, LUA_TSTRING); + std::string html = ls.toString(1); + + parseHtml(html); + + return 0; + } + int CGroupHTML::luaClearRefresh(CLuaState &ls) { const char *funcName = "clearRefresh"; @@ -6284,6 +6298,18 @@ namespace NLGUI browse(url.c_str()); } + // *************************************************************************** + bool CGroupHTML::parseHtml(const std::string &htmlString) + { + CHtmlParser html(this); + + bool result = html.parseHtml(htmlString); + if (result) + _DocumentHtml = htmlString; + + return result; + } + // *************************************************************************** inline bool isDigit(ucchar c, uint base = 16) { diff --git a/code/nel/src/gui/group_html_parser.cpp b/code/nel/src/gui/html_parser.cpp similarity index 89% rename from code/nel/src/gui/group_html_parser.cpp rename to code/nel/src/gui/html_parser.cpp index 0069fd77d..8470d0524 100644 --- a/code/nel/src/gui/group_html_parser.cpp +++ b/code/nel/src/gui/html_parser.cpp @@ -17,13 +17,14 @@ #include "stdpch.h" +#include "nel/gui/html_parser.h" + #include #include #include "nel/misc/types_nl.h" #include "nel/gui/libwww.h" #include "nel/gui/group_html.h" -#include "nel/gui/lua_ihm.h" using namespace std; using namespace NLMISC; @@ -35,7 +36,7 @@ using namespace NLMISC; namespace NLGUI { // *************************************************************************** - void CGroupHTML::htmlElement(xmlNode *node, int element_number) + void CHtmlParser::htmlElement(xmlNode *node, int element_number) { SGML_dtd *HTML_DTD = HTML_dtd (); @@ -65,30 +66,30 @@ namespace NLGUI } } - beginElement(element_number, present, value); + _GroupHtml->beginElement(element_number, present, value); } else { - beginUnparsedElement((const char *)(node->name), xmlStrlen(node->name)); + _GroupHtml->beginUnparsedElement((const char *)(node->name), xmlStrlen(node->name)); } // recursive - text content / child nodes - htmlWalkDOM(node->children); + parseNode(node->children); // closing tag if (element_number < HTML_ELEMENTS) { - endElement(element_number); + _GroupHtml->endElement(element_number); } else { - endUnparsedElement((const char *)(node->name), xmlStrlen(node->name)); + _GroupHtml->endUnparsedElement((const char *)(node->name), xmlStrlen(node->name)); } } // *************************************************************************** // recursive function to walk html document - void CGroupHTML::htmlWalkDOM(xmlNode *a_node) + void CHtmlParser::parseNode(xmlNode *a_node) { SGML_dtd *HTML_DTD = HTML_dtd (); @@ -98,7 +99,7 @@ namespace NLGUI { if (node->type == XML_TEXT_NODE) { - addText((const char *)(node->content), xmlStrlen(node->content)); + _GroupHtml->addText((const char *)(node->content), xmlStrlen(node->content)); } else if (node->type == XML_ELEMENT_NODE) @@ -297,7 +298,7 @@ namespace NLGUI } // *************************************************************************** - bool CGroupHTML::parseHtml(std::string htmlString) + bool CHtmlParser::parseHtml(std::string htmlString) { htmlParserCtxtPtr parser = htmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL, XML_CHAR_ENCODING_UTF8); if (!parser) @@ -320,7 +321,7 @@ namespace NLGUI xmlNode *root = xmlDocGetRootElement(parser->myDoc); if (root) { - htmlWalkDOM(root); + parseNode(root); } else { @@ -339,18 +340,6 @@ namespace NLGUI return success; } - // *************************************************************************** - int CGroupHTML::luaParseHtml(CLuaState &ls) - { - const char *funcName = "parseHtml"; - CLuaIHM::checkArgCount(ls, funcName, 1); - CLuaIHM::checkArgType(ls, funcName, 1, LUA_TSTRING); - std::string html = ls.toString(1); - - parseHtml(html); - - return 0; - } - } + From c107bdc56f7e88aaf2ee310de29e07ea3008668f Mon Sep 17 00:00:00 2001 From: Nimetu Date: Fri, 29 Mar 2019 15:03:39 +0200 Subject: [PATCH 05/75] Changed: Split css style from CGroupHTML --HG-- branch : develop --- code/nel/include/nel/gui/css_parser.h | 39 + code/nel/include/nel/gui/css_style.h | 141 +++ code/nel/include/nel/gui/group_html.h | 96 +- code/nel/include/nel/gui/libwww.h | 7 +- code/nel/src/gui/css_parser.cpp | 58 ++ code/nel/src/gui/css_style.cpp | 496 ++++++++++ code/nel/src/gui/group_html.cpp | 1258 +++++-------------------- code/nel/src/gui/libwww.cpp | 362 +++++++ 8 files changed, 1342 insertions(+), 1115 deletions(-) create mode 100644 code/nel/include/nel/gui/css_parser.h create mode 100644 code/nel/include/nel/gui/css_style.h create mode 100644 code/nel/src/gui/css_parser.cpp create mode 100644 code/nel/src/gui/css_style.cpp 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..cb4cea62e --- /dev/null +++ b/code/nel/include/nel/gui/css_parser.h @@ -0,0 +1,39 @@ +// 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" + +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); + }; + +}//namespace + +#endif // CL_CSS_PARSER_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..2a854a6d9 --- /dev/null +++ b/code/nel/include/nel/gui/css_style.h @@ -0,0 +1,141 @@ +// 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" + +namespace NLGUI +{ + 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; + } + 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; + }; + + class CCssStyle { + public: + + + // 'browser' style, overwriten with '' + CStyleParams Root; + + // current element style + CStyleParams Current; + + 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; + + public: + void reset(); + + inline uint getFontSizeSmaller() const + { + if (Current.FontSize < 5) + return 3; + return Current.FontSize-2; + } + + inline void pushStyle() + { + _StyleStack.push_back(Current); + } + + inline void popStyle() + { + if (_StyleStack.empty()) + Current = Root; + else + { + Current = _StyleStack.back(); + _StyleStack.pop_back(); + } + } + + // apply style string to this.Root + void applyRootStyle(const std::string &styleString); + + // apply style string to this.Current + void applyStyle(const std::string &styleString); + + void applyCssMinMax(sint32 &width, sint32 &height, sint32 minw=0, sint32 minh=0, sint32 maxw=0, sint32 maxh=0) const; + + }; + +}//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 b21841f8c..d8935f431 100644 --- a/code/nel/include/nel/gui/group_html.h +++ b/code/nel/include/nel/gui/group_html.h @@ -24,12 +24,11 @@ #include "nel/gui/ctrl_button.h" #include "nel/gui/group_table.h" #include "nel/gui/libwww_types.h" +#include "nel/gui/css_style.h" // forward declaration typedef void CURLM; -typedef std::map TStyle; - namespace NLGUI { class CCtrlButton; @@ -76,58 +75,6 @@ namespace NLGUI 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 TImageType {NormalImage=0, OverImage}; @@ -535,33 +482,8 @@ 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; // Current link std::vector _Link; @@ -625,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 { @@ -794,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); diff --git a/code/nel/include/nel/gui/libwww.h b/code/nel/include/nel/gui/libwww.h index 84eeb01e9..d7fe1251c 100644 --- a/code/nel/include/nel/gui/libwww.h +++ b/code/nel/include/nel/gui/libwww.h @@ -276,9 +276,14 @@ namespace NLGUI HTML_ATTR(H6,STYLE), }; - #undef HTML_ATTR + // *************************************************************************** + // Read HTML color value from src and set dest + // Can handle #rgb(a), #rrggbb(aa) or rgb()/rgba(), hsl(), hsla() formats + // or color name directly + bool scanHTMLColor(const char *src, NLMISC::CRGBA &dest); + // *************************************************************************** // Read a CSS length value, return true if one of supported units '%, rem, em, px, pt' // On failure: 'value' and 'unit' values are undefined diff --git a/code/nel/src/gui/css_parser.cpp b/code/nel/src/gui/css_parser.cpp new file mode 100644 index 000000000..c45121824 --- /dev/null +++ b/code/nel/src/gui/css_parser.cpp @@ -0,0 +1,58 @@ +// 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 . + +#include "stdpch.h" + +#include +#include "nel/misc/types_nl.h" +#include "nel/gui/css_parser.h" +#include "nel/gui/css_style.h" + +using namespace NLMISC; + +#ifdef DEBUG_NEW +#define new DEBUG_NEW +#endif + +namespace NLGUI +{ + // *************************************************************************** + // Parse style declarations style, eg. "color:red; font-size: 10px;" + // + // key is converted to lowercase + // value is left as is + TStyle CCssParser::parseDecls(const std::string &styleString) + { + TStyle styles; + std::vector elements; + NLMISC::splitString(styleString, ";", elements); + + for(uint i = 0; i < elements.size(); ++i) + { + std::string::size_type pos; + pos = elements[i].find_first_of(':'); + if (pos != std::string::npos) + { + std::string key = trim(toLower(elements[i].substr(0, pos))); + std::string value = trim(elements[i].substr(pos+1)); + styles[key] = value; + } + } + + return styles; + } +} // namespace + diff --git a/code/nel/src/gui/css_style.cpp b/code/nel/src/gui/css_style.cpp new file mode 100644 index 000000000..9d4b665bb --- /dev/null +++ b/code/nel/src/gui/css_style.cpp @@ -0,0 +1,496 @@ +// 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 . + +#include "stdpch.h" + +#include +#include "nel/misc/types_nl.h" +#include "nel/gui/css_style.h" +#include "nel/gui/css_parser.h" +#include "nel/gui/libwww.h" + +using namespace NLMISC; + +#ifdef DEBUG_NEW +#define new DEBUG_NEW +#endif + +namespace NLGUI +{ + // *************************************************************************** + void CCssStyle::reset() + { + _StyleStack.clear(); + + Root = CStyleParams(); + Current = CStyleParams(); + } + + // *************************************************************************** + void CCssStyle::applyRootStyle(const std::string &styleString) + { + getStyleParams(styleString, Root, Root); + } + + // *************************************************************************** + void CCssStyle::applyStyle(const std::string &styleString) + { + if (_StyleStack.empty()) + { + getStyleParams(styleString, Current, Root); + } + else + { + getStyleParams(styleString, Current, _StyleStack.back()); + } + } + + bool CCssStyle::scanCssLength(const std::string& str, uint32 &px) const + { + if (fromString(str, px)) + return true; + + if (str == "thin") + { + px = 1; + return true; + } + if (str == "medium") + { + px = 3; + return true; + } + if (str == "thick") + { + px = 5; + return true; + } + + return false; + } + + // *************************************************************************** + // CStyleParams style; + // style.FontSize; // font-size: 10px; + // style.TextColor; // color: #ABCDEF; + // style.Underlined; // text-decoration: underline; text-decoration-line: underline; + // style.StrikeThrough; // text-decoration: line-through; text-decoration-line: line-through; + void CCssStyle::getStyleParams(const std::string &styleString, CStyleParams &style, const CStyleParams ¤t) const + { + float tmpf; + TStyle styles = CCssParser::parseDecls(styleString); + TStyle::iterator it; + + // first pass: get font-size for 'em' sizes + for (it=styles.begin(); it != styles.end(); ++it) + { + if (it->first == "font") + { + if (it->second == "inherit") + { + style.FontSize = current.FontSize; + style.FontFamily = current.FontFamily; + style.FontWeight = current.FontWeight; + style.FontOblique = current.FontOblique; + } + } + else + if (it->first == "font-size") + { + if (it->second == "inherit") + { + style.FontSize = current.FontSize; + } + else + { + std::string unit; + if (getCssLength(tmpf, unit, it->second.c_str())) + { + if (unit == "rem") + style.FontSize = Root.FontSize * tmpf; + else if (unit == "em") + style.FontSize = current.FontSize * tmpf; + else if (unit == "pt") + style.FontSize = tmpf / 0.75f; + else if (unit == "%") + style.FontSize = current.FontSize * tmpf / 100.f; + else + style.FontSize = tmpf; + } + } + } + } + + // second pass: rest of style + for (it=styles.begin(); it != styles.end(); ++it) + { + if (it->first == "border") + { + sint32 b; + if (it->second == "none") + style.BorderWidth = 0; + else + if (fromString(it->second, b)) + style.BorderWidth = b; + } + else + if (it->first == "font-style") + { + if (it->second == "inherit") + style.FontOblique = current.FontOblique; + else + if (it->second == "italic" || it->second == "oblique") + style.FontOblique = true; + } + else + if (it->first == "font-family") + { + if (it->second == "inherit") + style.FontFamily = current.FontFamily; + else + style.FontFamily = it->second; + } + else + if (it->first == "font-weight") + { + // https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight + uint weight = 400; + if (it->second == "inherit") + weight = current.FontWeight; + else + if (it->second == "normal") + weight = 400; + else + if (it->second == "bold") + weight = 700; + else + if (it->second == "lighter") + { + const uint lighter[] = {100, 100, 100, 100, 100, 400, 400, 700, 700}; + uint index = current.FontWeight / 100 - 1; + clamp(index, 1u, 9u); + weight = lighter[index-1]; + } + else + if (it->second == "bolder") + { + const uint bolder[] = {400, 400, 400, 700, 700, 900, 900, 900, 900}; + uint index = current.FontWeight / 100 + 1; + clamp(index, 1u, 9u); + weight = bolder[index-1]; + } + else + if (fromString(it->second, weight)) + { + weight = (weight / 100); + clamp(weight, 1u, 9u); + weight *= 100; + } + style.FontWeight = weight; + } + else + if (it->first == "color") + if (it->second == "inherit") + style.TextColor = current.TextColor; + else + scanHTMLColor(it->second.c_str(), style.TextColor); + else + if (it->first == "text-decoration" || it->first == "text-decoration-line") + { + std::string prop(toLower(it->second)); + style.Underlined = (prop.find("underline") != std::string::npos); + style.StrikeThrough = (prop.find("line-through") != std::string::npos); + } + else + if (it->first == "text-stroke" || it->first == "-webkit-text-stroke") + { + // text-stroke: length || color + bool success = false; + uint px = 0; + CRGBA color; + std::vector parts; + NLMISC::splitString(it->second, " ", parts); + if (parts.size() == 1) + { + success = scanCssLength(parts[0], px); + if (!success) + success = scanHTMLColor(parts[0].c_str(), color); + } + else if (parts.size() == 2) + { + success = scanCssLength(parts[0], px); + if (success) + success = scanHTMLColor(parts[1].c_str(), color); + else + { + success = scanHTMLColor(parts[0].c_str(), color); + success = success && scanCssLength(parts[1], px); + } + } + + // do not disable shadow if one is already set + if (success) + { + style.TextShadow.Enabled = (px > 0); + style.TextShadow.Color = color; + style.TextShadow.X = px; + style.TextShadow.Y = px; + style.TextShadow.Outline = true; + } + } + else + if (it->first == "text-shadow") + { + if (it->second == "none") + style.TextShadow = CStyleParams::STextShadow(false); + else + if (it->second == "inherit") + style.TextShadow = current.TextShadow; + else + { + // text-shadow: offset-x offset-y | blur | #color + // text-shadow: #color | offset-x offset-y + bool success = true; + std::string prop(it->second); + size_t pos; + pos = prop.find_first_of(",\n\r"); + if (pos != std::string::npos) + prop = prop.substr(0, pos); + + std::vector parts; + NLMISC::splitString(prop, " ", parts); + switch(parts.size()) + { + case 1: + { + success = scanHTMLColor(it->second.c_str(), style.TextShadow.Color); + break; + } + // no case 2: + case 3: + { + if (!fromString(parts[0], style.TextShadow.X)) + { + success = scanHTMLColor(parts[0].c_str(), style.TextShadow.Color); + success = success && fromString(parts[1], style.TextShadow.X); + success = success && fromString(parts[2], style.TextShadow.Y); + } + else + { + success = fromString(parts[1], style.TextShadow.Y); + success = success && scanHTMLColor(parts[2].c_str(), style.TextShadow.Color); + } + break; + } + case 4: + { + if (!fromString(parts[0], style.TextShadow.X)) + { + success = scanHTMLColor(parts[0].c_str(), style.TextShadow.Color); + success = success && fromString(parts[1], style.TextShadow.X); + success = success && fromString(parts[2], style.TextShadow.Y); + // ignore blur [3] + } + else + { + success = fromString(parts[0], style.TextShadow.X); + success = success && fromString(parts[1], style.TextShadow.Y); + // ignore blur [2] + success = success && scanHTMLColor(parts[3].c_str(), style.TextShadow.Color); + } + break; + } + default: + { + // unsupported rule + break; + } + } + + style.TextShadow.Enabled = success; + } + } + else + if (it->first == "width") + { + std::string unit; + if (getCssLength(tmpf, unit, it->second.c_str())) + { + if (unit == "rem") + style.Width = tmpf * Root.FontSize; + else if (unit == "em") + style.Width = tmpf * style.FontSize; + else if (unit == "pt") + style.FontSize = tmpf / 0.75f; + else + style.Width = tmpf; + } + } + else + if (it->first == "height") + { + std::string unit; + if (getCssLength(tmpf, unit, it->second.c_str())) + { + if (unit == "rem") + style.Height = tmpf * Root.FontSize; + else if (unit == "em") + style.Height = tmpf * style.FontSize; + else if (unit == "pt") + style.FontSize = tmpf / 0.75f; + else + style.Height = tmpf; + } + } + else + if (it->first == "max-width") + { + std::string unit; + if (getCssLength(tmpf, unit, it->second.c_str())) + { + if (unit == "rem") + style.MaxWidth = tmpf * Root.FontSize; + else if (unit == "em") + style.MaxWidth = tmpf * style.FontSize; + else if (unit == "pt") + style.FontSize = tmpf / 0.75f; + else + style.MaxWidth = tmpf; + } + } + else + if (it->first == "max-height") + { + std::string unit; + if (getCssLength(tmpf, unit, it->second.c_str())) + { + if (unit == "rem") + style.MaxHeight = tmpf * Root.FontSize; + else if (unit == "em") + style.MaxHeight = tmpf * style.FontSize; + else if (unit == "pt") + style.FontSize = tmpf / 0.75f; + else + style.MaxHeight = tmpf; + } + } + else + if (it->first == "-ryzom-modulate-color") + { + bool b; + if (it->second == "inherit") + style.GlobalColor = current.GlobalColor; + else + if (fromString(it->second, b)) + style.GlobalColor = b; + } + else + if (it->first == "background-color") + { + if (it->second == "inherit") + style.BackgroundColor = current.BackgroundColor; + else + scanHTMLColor(it->second.c_str(), style.BackgroundColor); + } + else + if (it->first == "-ryzom-background-color-over") + { + if (it->second == "inherit") + style.BackgroundColorOver = current.BackgroundColorOver; + else + scanHTMLColor(it->second.c_str(), style.BackgroundColorOver); + } + } + + // if outer element has underline set, then inner element cannot remove it + if (current.Underlined) + style.Underlined = current.Underlined; + + // if outer element has line-through set, then inner element cannot remove it + if (current.StrikeThrough) + style.StrikeThrough = current.StrikeThrough; + } + + // *************************************************************************** + void CCssStyle::applyCssMinMax(sint32 &width, sint32 &height, sint32 minw, sint32 minh, sint32 maxw, sint32 maxh) const + { + if (maxw <= 0) maxw = width; + if (maxh <= 0) maxh = height; + + maxw = std::max(minw, maxw); + maxh = std::max(minh, maxh); + + float ratio = (float) width / std::max(1, height); + if (width > maxw) + { + width = maxw; + height = std::max((sint32)(maxw /ratio), minh); + } + if (width < minw) + { + width = minw; + height = std::min((sint32)(minw / ratio), maxh); + } + if (height > maxh) + { + width = std::max((sint32)(maxh * ratio), minw); + height = maxh; + } + if (height < minh) + { + width = std::min((sint32)(minh * ratio), maxw); + height = minh; + } + if (width > maxw && height > maxh) + { + if (maxw/width <= maxh/height) + { + width = maxw; + height = std::max(minh, (sint32)(maxw / ratio)); + } + else + { + width = std::max(minw, (sint32)(maxh * ratio)); + height = maxh; + } + } + if (width < minw && height < minh) + { + if (minw / width <= minh / height) + { + width = std::min(maxw, (sint32)(minh * ratio)); + height = minh; + } + else + { + width = minw; + height = std::min(maxh, (sint32)(minw / ratio)); + } + } + if (width < minw && height > maxh) + { + width = minw; + height = maxh; + } + if (width > maxw && height < minh) + { + width = maxw; + height = minh; + } + } + +} // namespace + diff --git a/code/nel/src/gui/group_html.cpp b/code/nel/src/gui/group_html.cpp index 36d0eab7f..ba21c6af1 100644 --- a/code/nel/src/gui/group_html.cpp +++ b/code/nel/src/gui/group_html.cpp @@ -357,7 +357,7 @@ namespace NLGUI // apply max-width, max-height rules if asked if (maxw > -1 || maxh > -1) { - applyCssMinMax(width, height, 0, 0, maxw, maxh); + _Style.applyCssMinMax(width, height, 0, 0, maxw, maxh); changed = true; } @@ -386,29 +386,33 @@ namespace NLGUI void CGroupHTML::setTextButtonStyle(CCtrlTextButton *ctrlButton, const CStyleParams &style) { // this will also set size for treating it like "display: inline-block;" - if (style.Width > 0) ctrlButton->setWMin(_Style.Width); - if (style.Height > 0) ctrlButton->setHMin(_Style.Height); + if (style.Width > 0) ctrlButton->setWMin(style.Width); + if (style.Height > 0) ctrlButton->setHMin(style.Height); CViewText *pVT = ctrlButton->getViewText(); if (pVT) { - setTextStyle(pVT, _Style); + setTextStyle(pVT, style); } - if (_Style.BackgroundColor.A > 0) + if (style.BackgroundColor.A > 0) { - if (_Style.BackgroundColorOver.A == 0) - _Style.BackgroundColorOver = _Style.BackgroundColor; - - ctrlButton->setColor(_Style.BackgroundColor); - ctrlButton->setColorOver(_Style.BackgroundColorOver); + ctrlButton->setColor(style.BackgroundColor); + if (style.BackgroundColorOver.A == 0) + { + ctrlButton->setColorOver(style.BackgroundColor); + } + else + { + ctrlButton->setColorOver(style.BackgroundColorOver); + } ctrlButton->setTexture("", "blank.tga", "", false); ctrlButton->setTextureOver("", "blank.tga", ""); ctrlButton->setProperty("force_text_over", "true"); } - else if (_Style.BackgroundColorOver.A > 0) + else if (style.BackgroundColorOver.A > 0) { - ctrlButton->setColorOver(_Style.BackgroundColorOver); + ctrlButton->setColorOver(style.BackgroundColorOver); ctrlButton->setProperty("force_text_over", "true"); ctrlButton->setTextureOver("blank.tga", "blank.tga", "blank.tga"); } @@ -1027,7 +1031,7 @@ namespace NLGUI TStyle CGroupHTML::parseStyle (const string &str_styles) { - TStyle styles; + TStyle styles; vector elements; NLMISC::splitString(str_styles, ";", elements); @@ -1149,392 +1153,6 @@ namespace NLGUI _CellParams.push_back (cellParams); \ } - static bool scanCssLength(const std::string& str, uint32 &px) - { - if (fromString(str, px)) - return true; - - if (str == "thin") - { - px = 1; - return true; - } - if (str == "medium") - { - px = 3; - return true; - } - if (str == "thick") - { - px = 5; - return true; - } - - return false; - } - - static bool isHexa(char c) - { - return isdigit(c) || (tolower(c) >= 'a' && tolower(c) <= 'f'); - } - - static uint8 convertHexa(char c) - { - return (uint8) (tolower(c) - (isdigit(c) ? '0' : ('a' - 10))); - } - - // scan a color component, and return pointer to next position - static const char *scanColorComponent(const char *src, uint8 &intensity) - { - if (!src) return NULL; - if (!isHexa(*src)) return NULL; - uint8 value = convertHexa(*src++) << 4; - if (!isHexa(*src)) return NULL; - value += convertHexa(*src++); - intensity = value; - return src; - } - - static float hueToRgb(float m1, float m2, float h) - { - if (h < 0) h += 1.0f; - if (h > 1) h -= 1.0f; - if (h*6 < 1.0f) return m1 + (m2 - m1)*h*6; - if (h*2 < 1.0f) return m2; - if (h*3 < 2.0f) return m1 + (m2 - m1) * (2.0f/3.0f - h)*6; - return m1; - } - - static void hslToRgb(float h, float s, float l, CRGBA &result) - { - float m1, m2; - if (l <= 0.5f) - m2 = l * (s + 1.0f); - else - m2 = l + s - l * s; - m1 = l*2 - m2; - - result.R = 255 * hueToRgb(m1, m2, h + 1.0f/3.0f); - result.G = 255 * hueToRgb(m1, m2, h); - result.B = 255 * hueToRgb(m1, m2, h - 1.0f/3.0f); - result.A = 255; - } - - class CNameToCol - { - public: - const char *Name; - CRGBA Color; - CNameToCol(const char *name, CRGBA color) : Name(name), Color(color) {} - }; - - static CNameToCol htmlColorNameToRGBA[] = - { - CNameToCol("AliceBlue", CRGBA(0xF0, 0xF8, 0xFF)), - CNameToCol("AntiqueWhite", CRGBA(0xFA, 0xEB, 0xD7)), - CNameToCol("Aqua", CRGBA(0x00, 0xFF, 0xFF)), - CNameToCol("Aquamarine", CRGBA(0x7F, 0xFF, 0xD4)), - CNameToCol("Azure", CRGBA(0xF0, 0xFF, 0xFF)), - CNameToCol("Beige", CRGBA(0xF5, 0xF5, 0xDC)), - CNameToCol("Bisque", CRGBA(0xFF, 0xE4, 0xC4)), - CNameToCol("Black", CRGBA(0x00, 0x00, 0x00)), - CNameToCol("BlanchedAlmond", CRGBA(0xFF, 0xEB, 0xCD)), - CNameToCol("Blue", CRGBA(0x00, 0x00, 0xFF)), - CNameToCol("BlueViolet", CRGBA(0x8A, 0x2B, 0xE2)), - CNameToCol("Brown", CRGBA(0xA5, 0x2A, 0x2A)), - CNameToCol("BurlyWood", CRGBA(0xDE, 0xB8, 0x87)), - CNameToCol("CadetBlue", CRGBA(0x5F, 0x9E, 0xA0)), - CNameToCol("Chartreuse", CRGBA(0x7F, 0xFF, 0x00)), - CNameToCol("Chocolate", CRGBA(0xD2, 0x69, 0x1E)), - CNameToCol("Coral", CRGBA(0xFF, 0x7F, 0x50)), - CNameToCol("CornflowerBlue", CRGBA(0x64, 0x95, 0xED)), - CNameToCol("Cornsilk", CRGBA(0xFF, 0xF8, 0xDC)), - CNameToCol("Crimson", CRGBA(0xDC, 0x14, 0x3C)), - CNameToCol("Cyan", CRGBA(0x00, 0xFF, 0xFF)), - CNameToCol("DarkBlue", CRGBA(0x00, 0x00, 0x8B)), - CNameToCol("DarkCyan", CRGBA(0x00, 0x8B, 0x8B)), - CNameToCol("DarkGoldenRod", CRGBA(0xB8, 0x86, 0x0B)), - CNameToCol("DarkGray", CRGBA(0xA9, 0xA9, 0xA9)), - CNameToCol("DarkGreen", CRGBA(0x00, 0x64, 0x00)), - CNameToCol("DarkKhaki", CRGBA(0xBD, 0xB7, 0x6B)), - CNameToCol("DarkMagenta", CRGBA(0x8B, 0x00, 0x8B)), - CNameToCol("DarkOliveGreen", CRGBA(0x55, 0x6B, 0x2F)), - CNameToCol("Darkorange", CRGBA(0xFF, 0x8C, 0x00)), - CNameToCol("DarkOrchid", CRGBA(0x99, 0x32, 0xCC)), - CNameToCol("DarkRed", CRGBA(0x8B, 0x00, 0x00)), - CNameToCol("DarkSalmon", CRGBA(0xE9, 0x96, 0x7A)), - CNameToCol("DarkSeaGreen", CRGBA(0x8F, 0xBC, 0x8F)), - CNameToCol("DarkSlateBlue", CRGBA(0x48, 0x3D, 0x8B)), - CNameToCol("DarkSlateGray", CRGBA(0x2F, 0x4F, 0x4F)), - CNameToCol("DarkTurquoise", CRGBA(0x00, 0xCE, 0xD1)), - CNameToCol("DarkViolet", CRGBA(0x94, 0x00, 0xD3)), - CNameToCol("DeepPink", CRGBA(0xFF, 0x14, 0x93)), - CNameToCol("DeepSkyBlue", CRGBA(0x00, 0xBF, 0xFF)), - CNameToCol("DimGray", CRGBA(0x69, 0x69, 0x69)), - CNameToCol("DodgerBlue", CRGBA(0x1E, 0x90, 0xFF)), - CNameToCol("Feldspar", CRGBA(0xD1, 0x92, 0x75)), - CNameToCol("FireBrick", CRGBA(0xB2, 0x22, 0x22)), - CNameToCol("FloralWhite", CRGBA(0xFF, 0xFA, 0xF0)), - CNameToCol("ForestGreen", CRGBA(0x22, 0x8B, 0x22)), - CNameToCol("Fuchsia", CRGBA(0xFF, 0x00, 0xFF)), - CNameToCol("Gainsboro", CRGBA(0xDC, 0xDC, 0xDC)), - CNameToCol("GhostWhite", CRGBA(0xF8, 0xF8, 0xFF)), - CNameToCol("Gold", CRGBA(0xFF, 0xD7, 0x00)), - CNameToCol("GoldenRod", CRGBA(0xDA, 0xA5, 0x20)), - CNameToCol("Gray", CRGBA(0x80, 0x80, 0x80)), - CNameToCol("Green", CRGBA(0x00, 0x80, 0x00)), - CNameToCol("GreenYellow", CRGBA(0xAD, 0xFF, 0x2F)), - CNameToCol("HoneyDew", CRGBA(0xF0, 0xFF, 0xF0)), - CNameToCol("HotPink", CRGBA(0xFF, 0x69, 0xB4)), - CNameToCol("IndianRed ", CRGBA(0xCD, 0x5C, 0x5C)), - CNameToCol("Indigo ", CRGBA(0x4B, 0x00, 0x82)), - CNameToCol("Ivory", CRGBA(0xFF, 0xFF, 0xF0)), - CNameToCol("Khaki", CRGBA(0xF0, 0xE6, 0x8C)), - CNameToCol("Lavender", CRGBA(0xE6, 0xE6, 0xFA)), - CNameToCol("LavenderBlush", CRGBA(0xFF, 0xF0, 0xF5)), - CNameToCol("LawnGreen", CRGBA(0x7C, 0xFC, 0x00)), - CNameToCol("LemonChiffon", CRGBA(0xFF, 0xFA, 0xCD)), - CNameToCol("LightBlue", CRGBA(0xAD, 0xD8, 0xE6)), - CNameToCol("LightCoral", CRGBA(0xF0, 0x80, 0x80)), - CNameToCol("LightCyan", CRGBA(0xE0, 0xFF, 0xFF)), - CNameToCol("LightGoldenRodYellow", CRGBA(0xFA, 0xFA, 0xD2)), - CNameToCol("LightGrey", CRGBA(0xD3, 0xD3, 0xD3)), - CNameToCol("LightGreen", CRGBA(0x90, 0xEE, 0x90)), - CNameToCol("LightPink", CRGBA(0xFF, 0xB6, 0xC1)), - CNameToCol("LightSalmon", CRGBA(0xFF, 0xA0, 0x7A)), - CNameToCol("LightSeaGreen", CRGBA(0x20, 0xB2, 0xAA)), - CNameToCol("LightSkyBlue", CRGBA(0x87, 0xCE, 0xFA)), - CNameToCol("LightSlateBlue", CRGBA(0x84, 0x70, 0xFF)), - CNameToCol("LightSlateGray", CRGBA(0x77, 0x88, 0x99)), - CNameToCol("LightSteelBlue", CRGBA(0xB0, 0xC4, 0xDE)), - CNameToCol("LightYellow", CRGBA(0xFF, 0xFF, 0xE0)), - CNameToCol("Lime", CRGBA(0x00, 0xFF, 0x00)), - CNameToCol("LimeGreen", CRGBA(0x32, 0xCD, 0x32)), - CNameToCol("Linen", CRGBA(0xFA, 0xF0, 0xE6)), - CNameToCol("Magenta", CRGBA(0xFF, 0x00, 0xFF)), - CNameToCol("Maroon", CRGBA(0x80, 0x00, 0x00)), - CNameToCol("MediumAquaMarine", CRGBA(0x66, 0xCD, 0xAA)), - CNameToCol("MediumBlue", CRGBA(0x00, 0x00, 0xCD)), - CNameToCol("MediumOrchid", CRGBA(0xBA, 0x55, 0xD3)), - CNameToCol("MediumPurple", CRGBA(0x93, 0x70, 0xD8)), - CNameToCol("MediumSeaGreen", CRGBA(0x3C, 0xB3, 0x71)), - CNameToCol("MediumSlateBlue", CRGBA(0x7B, 0x68, 0xEE)), - CNameToCol("MediumSpringGreen", CRGBA(0x00, 0xFA, 0x9A)), - CNameToCol("MediumTurquoise", CRGBA(0x48, 0xD1, 0xCC)), - CNameToCol("MediumVioletRed", CRGBA(0xC7, 0x15, 0x85)), - CNameToCol("MidnightBlue", CRGBA(0x19, 0x19, 0x70)), - CNameToCol("MintCream", CRGBA(0xF5, 0xFF, 0xFA)), - CNameToCol("MistyRose", CRGBA(0xFF, 0xE4, 0xE1)), - CNameToCol("Moccasin", CRGBA(0xFF, 0xE4, 0xB5)), - CNameToCol("NavajoWhite", CRGBA(0xFF, 0xDE, 0xAD)), - CNameToCol("Navy", CRGBA(0x00, 0x00, 0x80)), - CNameToCol("OldLace", CRGBA(0xFD, 0xF5, 0xE6)), - CNameToCol("Olive", CRGBA(0x80, 0x80, 0x00)), - CNameToCol("OliveDrab", CRGBA(0x6B, 0x8E, 0x23)), - CNameToCol("Orange", CRGBA(0xFF, 0xA5, 0x00)), - CNameToCol("OrangeRed", CRGBA(0xFF, 0x45, 0x00)), - CNameToCol("Orchid", CRGBA(0xDA, 0x70, 0xD6)), - CNameToCol("PaleGoldenRod", CRGBA(0xEE, 0xE8, 0xAA)), - CNameToCol("PaleGreen", CRGBA(0x98, 0xFB, 0x98)), - CNameToCol("PaleTurquoise", CRGBA(0xAF, 0xEE, 0xEE)), - CNameToCol("PaleVioletRed", CRGBA(0xD8, 0x70, 0x93)), - CNameToCol("PapayaWhip", CRGBA(0xFF, 0xEF, 0xD5)), - CNameToCol("PeachPuff", CRGBA(0xFF, 0xDA, 0xB9)), - CNameToCol("Peru", CRGBA(0xCD, 0x85, 0x3F)), - CNameToCol("Pink", CRGBA(0xFF, 0xC0, 0xCB)), - CNameToCol("Plum", CRGBA(0xDD, 0xA0, 0xDD)), - CNameToCol("PowderBlue", CRGBA(0xB0, 0xE0, 0xE6)), - CNameToCol("Purple", CRGBA(0x80, 0x00, 0x80)), - CNameToCol("Red", CRGBA(0xFF, 0x00, 0x00)), - CNameToCol("RosyBrown", CRGBA(0xBC, 0x8F, 0x8F)), - CNameToCol("RoyalBlue", CRGBA(0x41, 0x69, 0xE1)), - CNameToCol("SaddleBrown", CRGBA(0x8B, 0x45, 0x13)), - CNameToCol("Salmon", CRGBA(0xFA, 0x80, 0x72)), - CNameToCol("SandyBrown", CRGBA(0xF4, 0xA4, 0x60)), - CNameToCol("SeaGreen", CRGBA(0x2E, 0x8B, 0x57)), - CNameToCol("SeaShell", CRGBA(0xFF, 0xF5, 0xEE)), - CNameToCol("Sienna", CRGBA(0xA0, 0x52, 0x2D)), - CNameToCol("Silver", CRGBA(0xC0, 0xC0, 0xC0)), - CNameToCol("SkyBlue", CRGBA(0x87, 0xCE, 0xEB)), - CNameToCol("SlateBlue", CRGBA(0x6A, 0x5A, 0xCD)), - CNameToCol("SlateGray", CRGBA(0x70, 0x80, 0x90)), - CNameToCol("Snow", CRGBA(0xFF, 0xFA, 0xFA)), - CNameToCol("SpringGreen", CRGBA(0x00, 0xFF, 0x7F)), - CNameToCol("SteelBlue", CRGBA(0x46, 0x82, 0xB4)), - CNameToCol("Tan", CRGBA(0xD2, 0xB4, 0x8C)), - CNameToCol("Teal", CRGBA(0x00, 0x80, 0x80)), - CNameToCol("Thistle", CRGBA(0xD8, 0xBF, 0xD8)), - CNameToCol("Tomato", CRGBA(0xFF, 0x63, 0x47)), - CNameToCol("Turquoise", CRGBA(0x40, 0xE0, 0xD0)), - CNameToCol("Violet", CRGBA(0xEE, 0x82, 0xEE)), - CNameToCol("VioletRed", CRGBA(0xD0, 0x20, 0x90)), - CNameToCol("Wheat", CRGBA(0xF5, 0xDE, 0xB3)), - CNameToCol("White", CRGBA(0xFF, 0xFF, 0xFF)), - CNameToCol("WhiteSmoke", CRGBA(0xF5, 0xF5, 0xF5)), - CNameToCol("Yellow", CRGBA(0xFF, 0xFF, 0x00)), - CNameToCol("YellowGreen", CRGBA(0x9A, 0xCD, 0x32)) - }; - - // scan a color from a HTML form (#rrggbb format) - bool scanHTMLColor(const char *src, CRGBA &dest) - { - if (!src || *src == '\0') return false; - if (*src == '#') - { - ++src; - if (strlen(src) == 3 || strlen(src) == 4) - { - bool hasAlpha = (strlen(src) == 4); - // check RGB for valid hex - if (isHexa(src[0]) && isHexa(src[1]) && isHexa(src[2])) - { - // check optional A for valid hex - if (hasAlpha && !isHexa(src[3])) return false; - - dest.R = convertHexa(src[0]); - dest.G = convertHexa(src[1]); - dest.B = convertHexa(src[2]); - - dest.R = dest.R << 4 | dest.R; - dest.G = dest.G << 4 | dest.G; - dest.B = dest.B << 4 | dest.B; - - if (hasAlpha) - { - dest.A = convertHexa(src[3]); - dest.A = dest.A << 4 | dest.A; - } - else - dest.A = 255; - - return true; - } - - return false; - } - - CRGBA result; - src = scanColorComponent(src, result.R); if (!src) return false; - src = scanColorComponent(src, result.G); if (!src) return false; - src = scanColorComponent(src, result.B); if (!src) return false; - src = scanColorComponent(src, result.A); - if (!src) - { - // Alpha is optional - result.A = 255; - } - dest = result; - return true; - } - - if (strnicmp(src, "rgb(", 4) == 0 || strnicmp(src, "rgba(", 5) == 0) - { - src += 4; - if (*src == '(') src++; - - vector parts; - NLMISC::splitString(src, ",", parts); - if (parts.size() >= 3) - { - CRGBA result; - sint tmpv; - float tmpf; - - // R - if (getPercentage(tmpv, tmpf, parts[0].c_str())) tmpv = 255 * tmpf; - clamp(tmpv, 0, 255); - result.R = tmpv; - - // G - if (getPercentage(tmpv, tmpf, parts[1].c_str())) tmpv = 255 * tmpf; - clamp(tmpv, 0, 255); - result.G = tmpv; - - // B - if (getPercentage(tmpv, tmpf, parts[2].c_str())) tmpv = 255 * tmpf; - clamp(tmpv, 0, 255); - result.B = tmpv; - - // A - if (parts.size() == 4) - { - if (!fromString(parts[3], tmpf)) return false; - if (parts[3].find_first_of("%") != std::string::npos) - tmpf /= 100; - - tmpv = 255 * tmpf; - clamp(tmpv, 0, 255); - result.A = tmpv; - } - else - result.A = 255; - - dest = result; - return true; - } - - return false; - } - - if (strnicmp(src, "hsl(", 4) == 0 || strnicmp(src, "hsla(", 5) == 0) - { - src += 4; - if (*src == '(') src++; - - vector parts; - NLMISC::splitString(src, ",", parts); - if (parts.size() >= 3) - { - sint tmpv; - float h, s, l; - // hue - if (!fromString(parts[0], tmpv)) return false; - tmpv = ((tmpv % 360) + 360) % 360; - h = (float) tmpv / 360.0f; - - // saturation - if (!getPercentage(tmpv, s, parts[1].c_str())) return false; - clamp(s, 0.0f, 1.0f); - - // lightness - if (!getPercentage(tmpv, l, parts[2].c_str())) return false; - clamp(l, 0.0f, 1.0f); - - CRGBA result; - hslToRgb(h, s, l, result); - - // A - if (parts.size() == 4) - { - float tmpf; - if (!fromString(parts[3], tmpf)) return false; - if (parts[3].find_first_of("%") != std::string::npos) - tmpf /= 100; - clamp(tmpf, 0.0f, 1.0f); - result.A = 255 * tmpf; - } - - dest = result; - return true; - } - - return false; - } - - { - // slow but should suffice for now - for(uint k = 0; k < sizeofarray(htmlColorNameToRGBA); ++k) - { - if (nlstricmp(src, htmlColorNameToRGBA[k].Name) == 0) - { - dest = htmlColorNameToRGBA[k].Color; - return true; - } - } - return false; - } - } - // *************************************************************************** void CGroupHTML::beginElement (uint element_number, const std::vector &present, const std::vector &value) @@ -1546,10 +1164,10 @@ namespace NLGUI { case HTML_HTML: if (present[MY_HTML_HTML_STYLE] && value[MY_HTML_HTML_STYLE]) - getStyleParams(value[MY_HTML_HTML_STYLE], _StyleDefault, _StyleDefault); + _Style.applyRootStyle(value[MY_HTML_HTML_STYLE]); - _Style = _StyleDefault; - setBackgroundColor(_Style.BackgroundColor); + _Style.Current = _Style.Root; + setBackgroundColor(_Style.Current.BackgroundColor); break; case HTML_HEAD: _ReadingHeadTag = !_IgnoreHeadTag; @@ -1607,17 +1225,17 @@ namespace NLGUI { registerAnchorName(MY_HTML_A); - pushStyle(); - _Style.TextColor = LinkColor; - _Style.Underlined = true; - _Style.GlobalColor = LinkColorGlobalColor; - _Style.BackgroundColor.A = 0; - _Style.BackgroundColorOver.A = 0; - _Style.Width = -1; - _Style.Height = -1; + _Style.pushStyle(); + _Style.Current.TextColor = LinkColor; + _Style.Current.Underlined = true; + _Style.Current.GlobalColor = LinkColorGlobalColor; + _Style.Current.BackgroundColor.A = 0; + _Style.Current.BackgroundColorOver.A = 0; + _Style.Current.Width = -1; + _Style.Current.Height = -1; if (present[HTML_A_STYLE] && value[HTML_A_STYLE]) - getStyleParams(value[HTML_A_STYLE], _Style, _StyleParams.back()); + _Style.applyStyle(value[HTML_A_STYLE]); _A.push_back(true); _Link.push_back (""); @@ -1656,7 +1274,7 @@ namespace NLGUI { _BlockLevelElement.push_back(true); registerAnchorName(MY_HTML_DIV); - pushStyle(); + _Style.pushStyle(); if (present[MY_HTML_DIV_NAME] && value[MY_HTML_DIV_NAME]) _DivName = value[MY_HTML_DIV_NAME]; @@ -1670,7 +1288,7 @@ namespace NLGUI style = value[MY_HTML_DIV_STYLE]; if (!style.empty()) - getStyleParams(style, _Style, _StyleParams.back()); + _Style.applyStyle(style); // use generic template system if (_TrustedDomain && !instClass.empty() && instClass == "ryzom-ui-grouptemplate") @@ -1746,19 +1364,19 @@ namespace NLGUI break; case HTML_FONT: { - pushStyle(); + _Style.pushStyle(); if (present[HTML_FONT_COLOR] && value[HTML_FONT_COLOR]) { CRGBA color; if (scanHTMLColor(value[HTML_FONT_COLOR], color)) - _Style.TextColor = color; + _Style.Current.TextColor = color; } if (present[HTML_FONT_SIZE] && value[HTML_FONT_SIZE]) { uint fontsize; fromString(value[HTML_FONT_SIZE], fontsize); - _Style.FontSize = fontsize; + _Style.Current.FontSize = fontsize; } } break; @@ -1774,20 +1392,20 @@ namespace NLGUI break; case HTML_BODY: { - pushStyle(); + _Style.pushStyle(); string style; if (present[HTML_BODY_STYLE] && value[HTML_BODY_STYLE]) style = value[HTML_BODY_STYLE]; if (!style.empty()) - getStyleParams(style, _Style, _StyleParams.back()); + _Style.applyStyle(style); - CRGBA bgColor = _Style.BackgroundColor; + CRGBA bgColor = _Style.Current.BackgroundColor; if (present[HTML_BODY_BGCOLOR] && value[HTML_BODY_BGCOLOR]) scanHTMLColor(value[HTML_BODY_BGCOLOR], bgColor); - if (bgColor != _Style.BackgroundColor) + if (bgColor != _Style.Current.BackgroundColor) setBackgroundColor(bgColor); if (!style.empty()) @@ -1837,72 +1455,72 @@ namespace NLGUI { registerAnchorName(MY_HTML_H1); newParagraph(PBeginSpace); - pushStyle(); - _Style.FontSize = H1FontSize; - _Style.TextColor = H1Color; - _Style.GlobalColor = H1ColorGlobalColor; + _Style.pushStyle(); + _Style.Current.FontSize = H1FontSize; + _Style.Current.TextColor = H1Color; + _Style.Current.GlobalColor = H1ColorGlobalColor; if (present[MY_HTML_H1_STYLE] && value[MY_HTML_H1_STYLE]) - getStyleParams(value[MY_HTML_H1_STYLE], _Style, _StyleParams.back()); + _Style.applyStyle(value[MY_HTML_H1_STYLE]); } break; case HTML_H2: { registerAnchorName(MY_HTML_H2); newParagraph(PBeginSpace); - pushStyle(); - _Style.FontSize = H2FontSize; - _Style.TextColor = H2Color; - _Style.GlobalColor = H2ColorGlobalColor; + _Style.pushStyle(); + _Style.Current.FontSize = H2FontSize; + _Style.Current.TextColor = H2Color; + _Style.Current.GlobalColor = H2ColorGlobalColor; if (present[MY_HTML_H2_STYLE] && value[MY_HTML_H2_STYLE]) - getStyleParams(value[MY_HTML_H2_STYLE], _Style, _StyleParams.back()); + _Style.applyStyle(value[MY_HTML_H2_STYLE]); } break; case HTML_H3: { registerAnchorName(MY_HTML_H3); newParagraph(PBeginSpace); - pushStyle(); - _Style.FontSize = H3FontSize; - _Style.TextColor = H3Color; - _Style.GlobalColor = H3ColorGlobalColor; + _Style.pushStyle(); + _Style.Current.FontSize = H3FontSize; + _Style.Current.TextColor = H3Color; + _Style.Current.GlobalColor = H3ColorGlobalColor; if (present[MY_HTML_H3_STYLE] && value[MY_HTML_H3_STYLE]) - getStyleParams(value[MY_HTML_H3_STYLE], _Style, _StyleParams.back()); + _Style.applyStyle(value[MY_HTML_H3_STYLE]); } break; case HTML_H4: { registerAnchorName(MY_HTML_H4); newParagraph(PBeginSpace); - pushStyle(); - _Style.FontSize = H4FontSize; - _Style.TextColor = H4Color; - _Style.GlobalColor = H4ColorGlobalColor; + _Style.pushStyle(); + _Style.Current.FontSize = H4FontSize; + _Style.Current.TextColor = H4Color; + _Style.Current.GlobalColor = H4ColorGlobalColor; if (present[MY_HTML_H4_STYLE] && value[MY_HTML_H4_STYLE]) - getStyleParams(value[MY_HTML_H4_STYLE], _Style, _StyleParams.back()); + _Style.applyStyle(value[MY_HTML_H4_STYLE]); } break; case HTML_H5: { registerAnchorName(MY_HTML_H5); newParagraph(PBeginSpace); - pushStyle(); - _Style.FontSize = H5FontSize; - _Style.TextColor = H5Color; - _Style.GlobalColor = H5ColorGlobalColor; + _Style.pushStyle(); + _Style.Current.FontSize = H5FontSize; + _Style.Current.TextColor = H5Color; + _Style.Current.GlobalColor = H5ColorGlobalColor; if (present[MY_HTML_H5_STYLE] && value[MY_HTML_H5_STYLE]) - getStyleParams(value[MY_HTML_H5_STYLE], _Style, _StyleParams.back()); + _Style.applyStyle(value[MY_HTML_H5_STYLE]); } break; case HTML_H6: { registerAnchorName(MY_HTML_H6); newParagraph(PBeginSpace); - pushStyle(); - _Style.FontSize = H6FontSize; - _Style.TextColor = H6Color; - _Style.GlobalColor = H6ColorGlobalColor; + _Style.pushStyle(); + _Style.Current.FontSize = H6FontSize; + _Style.Current.TextColor = H6Color; + _Style.Current.GlobalColor = H6ColorGlobalColor; if (present[MY_HTML_H6_STYLE] && value[MY_HTML_H6_STYLE]) - getStyleParams(value[MY_HTML_H6_STYLE], _Style, _StyleParams.back()); + _Style.applyStyle(value[MY_HTML_H6_STYLE]); } break; case HTML_IMG: @@ -1912,24 +1530,24 @@ namespace NLGUI { float tmpf; std::string id; - CStyleParams style; - style.FontSize = _Style.FontSize; + + _Style.pushStyle(); if (present[MY_HTML_IMG_ID] && value[MY_HTML_IMG_ID]) id = value[MY_HTML_IMG_ID]; if (present[MY_HTML_IMG_WIDTH] && value[MY_HTML_IMG_WIDTH]) - getPercentage(style.Width, tmpf, value[MY_HTML_IMG_WIDTH]); + getPercentage(_Style.Current.Width, tmpf, value[MY_HTML_IMG_WIDTH]); if (present[MY_HTML_IMG_HEIGHT] && value[MY_HTML_IMG_HEIGHT]) - getPercentage(style.Height, tmpf, value[MY_HTML_IMG_HEIGHT]); + getPercentage(_Style.Current.Height, tmpf, value[MY_HTML_IMG_HEIGHT]); // Get the global color name if (present[MY_HTML_IMG_GLOBAL_COLOR]) - style.GlobalColor = true; + _Style.Current.GlobalColor = true; // width, height from inline css if (present[MY_HTML_IMG_STYLE] && value[MY_HTML_IMG_STYLE]) - getStyleParams(value[MY_HTML_IMG_STYLE], style, _Style); + _Style.applyStyle(value[MY_HTML_IMG_STYLE]); // Tooltip const char *tooltip = NULL; @@ -1952,13 +1570,13 @@ namespace NLGUI { string params = "name=" + getId() + "|url=" + getLink (); addButton(CCtrlButton::PushButton, id, value[MY_HTML_IMG_SRC], value[MY_HTML_IMG_SRC], - overSrc, "browse", params.c_str(), tooltip, style); + overSrc, "browse", params.c_str(), tooltip, _Style.Current); } else if (tooltip || !overSrc.empty()) { addButton(CCtrlButton::PushButton, id, value[MY_HTML_IMG_SRC], value[MY_HTML_IMG_SRC], - overSrc, "", "", tooltip, style); + overSrc, "", "", tooltip, _Style.Current); } else { @@ -1979,8 +1597,10 @@ namespace NLGUI reloadImg = true; } - addImage(id, value[MY_HTML_IMG_SRC], reloadImg, style); + addImage(id, value[MY_HTML_IMG_SRC], reloadImg, _Style.Current); } + + _Style.popStyle(); } } break; @@ -2010,22 +1630,22 @@ namespace NLGUI if (present[MY_HTML_INPUT_TYPE] && value[MY_HTML_INPUT_TYPE]) { // by default not inherited, font family defaults to system font - pushStyle(); - _Style.TextColor = TextColor; - _Style.FontSize = TextFontSize; - _Style.FontWeight = FONT_WEIGHT_NORMAL; - _Style.FontOblique = false; - _Style.TextShadow = STextShadow(true); - _Style.Width = -1; - _Style.Height = -1; + _Style.pushStyle(); + _Style.Current.TextColor = TextColor; + _Style.Current.FontSize = TextFontSize; + _Style.Current.FontWeight = FONT_WEIGHT_NORMAL; + _Style.Current.FontOblique = false; + _Style.Current.TextShadow = CStyleParams::STextShadow(true); + _Style.Current.Width = -1; + _Style.Current.Height = -1; // by default background texture is transparent, // using alpha value to decide if to change it to 'blank.tga' for coloring - _Style.BackgroundColor.A = 0; - _Style.BackgroundColorOver.A = 0; + _Style.Current.BackgroundColor.A = 0; + _Style.Current.BackgroundColorOver.A = 0; // Global color flag if (present[MY_HTML_INPUT_GLOBAL_COLOR]) - _Style.GlobalColor = true; + _Style.Current.GlobalColor = true; // Tooltip const char *tooltip = NULL; @@ -2033,7 +1653,7 @@ namespace NLGUI tooltip = value[MY_HTML_INPUT_ALT]; if (present[MY_HTML_INPUT_STYLE] && value[MY_HTML_INPUT_STYLE]) - getStyleParams(value[MY_HTML_INPUT_STYLE], _Style, _StyleParams.back()); + _Style.applyStyle(value[MY_HTML_INPUT_STYLE]); string type = toLower(value[MY_HTML_INPUT_TYPE]); if (type == "image") @@ -2053,7 +1673,7 @@ namespace NLGUI // Add the ctrl button addButton (CCtrlButton::PushButton, name, normal, pushed.empty()?normal:pushed, over, - "html_submit_form", param.c_str(), tooltip, _Style); + "html_submit_form", param.c_str(), tooltip, _Style.Current); } if (type == "button" || type == "submit") { @@ -2108,7 +1728,7 @@ namespace NLGUI if (!ctrlButton) ctrlButton = dynamic_cast(buttonGroup->getCtrl("b")); if (ctrlButton) { - ctrlButton->setModulateGlobalColorAll (_Style.GlobalColor); + ctrlButton->setModulateGlobalColorAll (_Style.Current.GlobalColor); // Translate the tooltip if (tooltip) @@ -2125,7 +1745,7 @@ namespace NLGUI ctrlButton->setText(ucstring::makeFromUtf8(text)); - setTextButtonStyle(ctrlButton, _Style); + setTextButtonStyle(ctrlButton, _Style.Current); } getParagraph()->addChild (buttonGroup); paragraphChange (); @@ -2193,7 +1813,7 @@ namespace NLGUI checked = (present[MY_HTML_INPUT_CHECKED] && value[MY_HTML_INPUT_CHECKED]); // Add the ctrl button - CCtrlButton *checkbox = addButton (btnType, name, normal, pushed, over, "", "", tooltip, _Style); + CCtrlButton *checkbox = addButton (btnType, name, normal, pushed, over, "", "", tooltip, _Style.Current); if (checkbox) { if (btnType == CCtrlButton::RadioButton) @@ -2251,14 +1871,16 @@ namespace NLGUI } } - popStyle(); + _Style.popStyle(); } } break; case HTML_SELECT: if (!(_Forms.empty())) { - CStyleParams style; + _Style.pushStyle(); + _Style.Current.Width = -1; + _Style.Current.Height = -1; // A select box string name; @@ -2272,7 +1894,7 @@ namespace NLGUI if (present[HTML_SELECT_MULTIPLE] && value[HTML_SELECT_MULTIPLE]) multiple = true; if (present[HTML_SELECT_STYLE] && value[HTML_SELECT_STYLE]) - getStyleParams(value[HTML_SELECT_STYLE], style, _Style); + _Style.applyStyle(value[HTML_SELECT_STYLE]); CGroupHTML::CForm::CEntry entry; entry.Name = name; @@ -2286,14 +1908,14 @@ namespace NLGUI if (size < 1) size = 4; - if (style.Width > -1) - sb->setMinW(style.Width); + if (_Style.Current.Width > -1) + sb->setMinW(_Style.Current.Width); - if (style.Height > -1) - sb->setMinH(style.Height); + if (_Style.Current.Height > -1) + sb->setMinH(_Style.Current.Height); sb->setMaxVisibleLine(size); - sb->setFontSize(style.FontSize); + sb->setFontSize(_Style.Current.FontSize); } entry.SelectBox = sb; @@ -2308,10 +1930,12 @@ namespace NLGUI // create view text cb->updateCoords(); if (cb->getViewText()) - setTextStyle(cb->getViewText(), style); + setTextStyle(cb->getViewText(), _Style.Current); } } _Forms.back().Entries.push_back (entry); + + _Style.popStyle(); } break; case HTML_OPTION: @@ -2354,9 +1978,9 @@ namespace NLGUI if (present[HTML_LI_VALUE] && value[HTML_LI_VALUE]) fromString(value[HTML_LI_VALUE], _UL.back().Value); - pushStyle(); + _Style.pushStyle(); if (present[HTML_LI_STYLE] && value[HTML_LI_STYLE]) - getStyleParams(value[HTML_LI_STYLE], _Style, _StyleParams.back()); + _Style.applyStyle(value[HTML_LI_STYLE]); ucstring str; str.fromUtf8(_UL.back().getListMarkerText()); @@ -2377,18 +2001,18 @@ namespace NLGUI case HTML_P: { newParagraph(PBeginSpace); - pushStyle(); + _Style.pushStyle(); if (present[MY_HTML_P_STYLE] && value[MY_HTML_P_STYLE]) - getStyleParams(value[MY_HTML_P_STYLE], _Style, _StyleParams.back()); + _Style.applyStyle(value[MY_HTML_P_STYLE]); } break; case HTML_PRE: { - pushStyle(); - _Style.FontFamily = "monospace"; + _Style.pushStyle(); + _Style.Current.FontFamily = "monospace"; if (present[HTML_PRE_STYLE] && value[HTML_PRE_STYLE]) - getStyleParams(value[HTML_PRE_STYLE], _Style, _StyleParams.back()); + _Style.applyStyle(value[HTML_PRE_STYLE]); _PRE.push_back(true); @@ -2396,7 +2020,7 @@ namespace NLGUI break; case HTML_TABLE: { - pushStyle(); + _Style.pushStyle(); registerAnchorName(MY_HTML_TABLE); // Get cells parameters @@ -2416,7 +2040,7 @@ namespace NLGUI if (present[MY_HTML_TABLE_CELLPADDING] && value[MY_HTML_TABLE_CELLPADDING]) fromString(value[MY_HTML_TABLE_CELLPADDING], table->CellPadding); if (present[MY_HTML_TABLE_STYLE] && value[MY_HTML_TABLE_STYLE]) - getStyleParams(value[MY_HTML_TABLE_STYLE], _Style, _StyleParams.back()); + _Style.applyStyle(value[MY_HTML_TABLE_STYLE]); table->setMarginLeft(getIndent()); addHtmlGroup (table, 0); @@ -2436,17 +2060,17 @@ namespace NLGUI // Get cells parameters getCellsParameters (MY_HTML_TD, true); - pushStyle(); + _Style.pushStyle(); if (element_number == HTML_TH) { - _Style.FontWeight = FONT_WEIGHT_BOLD; + _Style.Current.FontWeight = FONT_WEIGHT_BOLD; // center if not specified otherwise. TD/TH present/value arrays have same indices if (!(present[MY_HTML_TD_ALIGN] && value[MY_HTML_TD_ALIGN])) _CellParams.back().Align = CGroupCell::Center; } if (present[MY_HTML_TD_STYLE] && value[MY_HTML_TD_STYLE]) - getStyleParams(value[MY_HTML_TD_STYLE], _Style, _StyleParams.back()); + _Style.applyStyle(value[MY_HTML_TD_STYLE]); CGroupTable *table = getTable(); if (table) @@ -2527,21 +2151,21 @@ namespace NLGUI } break; case HTML_TEXTAREA: - pushStyle(); + _Style.pushStyle(); _PRE.push_back(true); // not inherited by default, font family defaults to system font - _Style.TextColor = TextColor; - _Style.FontWeight = FONT_WEIGHT_NORMAL; - _Style.FontOblique = false; - _Style.FontSize = TextFontSize; - _Style.TextShadow = STextShadow(true); - _Style.Width = -1; - _Style.Height = -1; - _Style.BackgroundColor.A = 0; + _Style.Current.TextColor = TextColor; + _Style.Current.FontWeight = FONT_WEIGHT_NORMAL; + _Style.Current.FontOblique = false; + _Style.Current.FontSize = TextFontSize; + _Style.Current.TextShadow = CStyleParams::STextShadow(true); + _Style.Current.Width = -1; + _Style.Current.Height = -1; + _Style.Current.BackgroundColor.A = 0; if (present[MY_HTML_TEXTAREA_STYLE] && value[MY_HTML_TEXTAREA_STYLE]) - getStyleParams(value[MY_HTML_TEXTAREA_STYLE], _Style, _StyleParams.back()); + _Style.applyStyle(value[MY_HTML_TEXTAREA_STYLE]); // Got one form ? if (!(_Forms.empty())) @@ -2595,9 +2219,9 @@ namespace NLGUI if (!_TR.empty()) _TR.back() = true; - pushStyle(); + _Style.pushStyle(); if (present[MY_HTML_TR_STYLE] && value[MY_HTML_TR_STYLE]) - getStyleParams(value[MY_HTML_TR_STYLE], _Style, _StyleParams.back()); + _Style.applyStyle(value[MY_HTML_TR_STYLE]); } break; case HTML_UL: @@ -2612,9 +2236,9 @@ namespace NLGUI _Indent.push_back(getIndent() + ULIndent); endParagraph(); - pushStyle(); + _Style.pushStyle(); if (present[HTML_UL_STYLE] && value[HTML_UL_STYLE]) - getStyleParams(value[HTML_UL_STYLE], _Style, _StyleParams.back()); + _Style.applyStyle(value[HTML_UL_STYLE]); break; case HTML_OBJECT: _ObjectType.clear(); @@ -2634,40 +2258,40 @@ namespace NLGUI break; case HTML_SPAN: { - pushStyle(); + _Style.pushStyle(); if (present[MY_HTML_SPAN_STYLE] && value[MY_HTML_SPAN_STYLE]) - getStyleParams(value[MY_HTML_SPAN_STYLE], _Style, _StyleParams.back()); + _Style.applyStyle(value[MY_HTML_SPAN_STYLE]); } break; case HTML_DEL: { - pushStyle(); - _Style.StrikeThrough = true; + _Style.pushStyle(); + _Style.Current.StrikeThrough = true; } break; case HTML_U: { - pushStyle(); - _Style.Underlined = true; + _Style.pushStyle(); + _Style.Current.Underlined = true; } break; case HTML_EM: { - pushStyle(); - _Style.FontOblique = true; + _Style.pushStyle(); + _Style.Current.FontOblique = true; } break; case HTML_STRONG: { - pushStyle(); - _Style.FontWeight = FONT_WEIGHT_BOLD; + _Style.pushStyle(); + _Style.Current.FontWeight = FONT_WEIGHT_BOLD; } break; case HTML_SMALL: { - pushStyle(); - _Style.FontSize = getFontSizeSmaller(); + _Style.pushStyle(); + _Style.Current.FontSize = _Style.getFontSizeSmaller(); } break; case HTML_STYLE: @@ -2679,9 +2303,9 @@ namespace NLGUI _DL.push_back(HTMLDListElement()); _LI = _DL.size() > 1 || !_UL.empty(); endParagraph(); - pushStyle(); + _Style.pushStyle(); if (present[HTML_GEN_STYLE] && value[HTML_GEN_STYLE]) - getStyleParams(value[HTML_GEN_STYLE], _Style, _StyleParams.back()); + _Style.applyStyle(value[HTML_GEN_STYLE]); } break; case HTML_DT: @@ -2692,19 +2316,19 @@ namespace NLGUI { _DL.back().DD = false; popIfNotEmpty(_Indent); - popStyle(); + _Style.popStyle(); } // close if still open if (_DL.back().DT) - popStyle(); + _Style.popStyle(); _DL.back().DT = true; - pushStyle(); - _Style.FontWeight = FONT_WEIGHT_BOLD; + _Style.pushStyle(); + _Style.Current.FontWeight = FONT_WEIGHT_BOLD; if (present[HTML_GEN_STYLE] && value[HTML_GEN_STYLE]) - getStyleParams(value[HTML_GEN_STYLE], _Style, _StyleParams.back()); + _Style.applyStyle(value[HTML_GEN_STYLE]); if (!_LI) { @@ -2724,22 +2348,22 @@ namespace NLGUI if (_DL.back().DT) { _DL.back().DT = false; - popStyle(); + _Style.popStyle(); } if (_DL.back().DD) { _DL.back().DD = false; - popStyle(); + _Style.popStyle(); popIfNotEmpty(_Indent); } _DL.back().DD = true; _Indent.push_back(getIndent() + ULIndent); - pushStyle(); + _Style.pushStyle(); if (present[HTML_GEN_STYLE] && value[HTML_GEN_STYLE]) - getStyleParams(value[HTML_GEN_STYLE], _Style, _StyleParams.back()); + _Style.applyStyle(value[HTML_GEN_STYLE]); if (!_LI) { @@ -2754,7 +2378,7 @@ namespace NLGUI break; case HTML_OL: { - pushStyle(); + _Style.pushStyle(); sint32 start = 1; std::string type("1"); @@ -2763,7 +2387,7 @@ namespace NLGUI if (present[HTML_OL_TYPE] && value[HTML_OL_TYPE]) type = value[HTML_OL_TYPE]; if (present[HTML_OL_STYLE] && value[HTML_OL_STYLE]) - getStyleParams(value[HTML_OL_STYLE], _Style, _StyleParams.back()); + _Style.applyStyle(value[HTML_OL_STYLE]); _UL.push_back(HTMLOListElement(start, type)); // if LI is already present @@ -2779,34 +2403,35 @@ namespace NLGUI CInterfaceGroup *sep = CWidgetManager::getInstance()->getParser()->createGroupInstance("html_hr", "", NULL, 0); if (sep) { - CStyleParams style; - style.FontSize = _Style.FontSize; - style.TextColor = CRGBA(120, 120, 120, 255); - style.Height = 0; - style.Width = 0; + _Style.pushStyle(); + _Style.Current.TextColor = CRGBA(120, 120, 120, 255); + _Style.Current.Height = -1; + _Style.Current.Width = -1; if (present[HTML_HR_STYLE] && value[HTML_HR_STYLE]) - getStyleParams(value[HTML_HR_STYLE], style, _Style); + _Style.applyStyle(value[HTML_HR_STYLE]); CViewBitmap *bitmap = dynamic_cast(sep->getView("hr")); if (bitmap) { - bitmap->setColor(style.TextColor); - if (style.Width > 0) + bitmap->setColor(_Style.Current.TextColor); + if (_Style.Current.Width > 0) { - clamp(style.Width, 1, 32000); - bitmap->setW(style.Width); + clamp(_Style.Current.Width, 1, 32000); + bitmap->setW(_Style.Current.Width); bitmap->setSizeRef(CInterfaceElement::none); } - if (style.Height > 0) + if (_Style.Current.Height > 0) { - clamp(style.Height, 1, 1000); - bitmap->setH(style.Height); + clamp(_Style.Current.Height, 1, 1000); + bitmap->setH(_Style.Current.Height); } } getParagraph()->addChild(sep); endParagraph(); + + _Style.popStyle(); } } break; @@ -2827,13 +2452,13 @@ namespace NLGUI _ReadingHeadTag = false; break; case HTML_BODY: - popStyle(); + _Style.popStyle(); break; case HTML_FONT: - popStyle(); + _Style.popStyle(); break; case HTML_A: - popStyle(); + _Style.popStyle(); popIfNotEmpty (_A); popIfNotEmpty (_Link); popIfNotEmpty (_LinkTitle); @@ -2845,19 +2470,19 @@ namespace NLGUI case HTML_H4: case HTML_H5: case HTML_H6: - popStyle(); + _Style.popStyle(); endParagraph(); break; case HTML_P: - popStyle(); + _Style.popStyle(); endParagraph(); break; case HTML_PRE: - popStyle(); + _Style.popStyle(); popIfNotEmpty (_PRE); break; case HTML_DIV: - popStyle(); + _Style.popStyle(); if (isBlockLevelElement()) { endParagraph(); @@ -2868,7 +2493,7 @@ namespace NLGUI break; case HTML_TABLE: - popStyle(); + _Style.popStyle(); popIfNotEmpty (_CellParams); popIfNotEmpty (_TR); popIfNotEmpty (_Cells); @@ -2880,13 +2505,13 @@ namespace NLGUI case HTML_TH: // no break; case HTML_TD: - popStyle(); + _Style.popStyle(); popIfNotEmpty (_CellParams); if (!_Cells.empty()) _Cells.back() = NULL; break; case HTML_TR: - popStyle(); + _Style.popStyle(); popIfNotEmpty (_CellParams); break; case HTML_TEXTAREA: @@ -2905,7 +2530,7 @@ namespace NLGUI } } - popStyle(); + _Style.popStyle(); popIfNotEmpty (_PRE); } break; @@ -3013,14 +2638,14 @@ namespace NLGUI if (!_UL.empty()) { endParagraph(); - popStyle(); + _Style.popStyle(); popIfNotEmpty(_UL); popIfNotEmpty(_Indent); } break; case HTML_LI: { - popStyle(); + _Style.popStyle(); } break; case HTML_DL: @@ -3031,25 +2656,25 @@ namespace NLGUI // unclosed DT if (_DL.back().DT) { - popStyle(); + _Style.popStyle(); } // unclosed DD if (_DL.back().DD) { popIfNotEmpty(_Indent); - popStyle(); + _Style.popStyle(); } popIfNotEmpty (_DL); - popStyle(); + _Style.popStyle(); } break; case HTML_DT: if (!_DL.empty()) { if (_DL.back().DT) - popStyle(); + _Style.popStyle(); _DL.back().DT = false; } break; @@ -3061,27 +2686,27 @@ namespace NLGUI { _DL.back().DD = false; popIfNotEmpty(_Indent); - popStyle(); + _Style.popStyle(); } } break; case HTML_SPAN: - popStyle(); + _Style.popStyle(); break; case HTML_DEL: - popStyle(); + _Style.popStyle(); break; case HTML_U: - popStyle(); + _Style.popStyle(); break; case HTML_EM: - popStyle(); + _Style.popStyle(); break; case HTML_STRONG: - popStyle(); + _Style.popStyle(); break; case HTML_SMALL: - popStyle(); + _Style.popStyle(); break; case HTML_STYLE: case HTML_SCRIPT: @@ -4508,34 +4133,36 @@ namespace NLGUI paragraphChange (); } + CStyleParams &style = _Style.Current; + // Text added ? bool added = false; - bool embolden = _Style.FontWeight >= FONT_WEIGHT_BOLD; + bool embolden = style.FontWeight >= FONT_WEIGHT_BOLD; // Number of child in this paragraph if (_CurrentViewLink) { bool skipLine = !_CurrentViewLink->getText().empty() && *(_CurrentViewLink->getText().rbegin()) == (ucchar) '\n'; - bool sameShadow = _Style.TextShadow.Enabled && _CurrentViewLink->getShadow(); - if (sameShadow && _Style.TextShadow.Enabled) + bool sameShadow = style.TextShadow.Enabled && _CurrentViewLink->getShadow(); + if (sameShadow && style.TextShadow.Enabled) { sint sx, sy; _CurrentViewLink->getShadowOffset(sx, sy); - sameShadow = (_Style.TextShadow.Color == _CurrentViewLink->getShadowColor()); - sameShadow = sameShadow && (_Style.TextShadow.Outline == _CurrentViewLink->getShadowOutline()); - sameShadow = sameShadow && (_Style.TextShadow.X == sx) && (_Style.TextShadow.Y == sy); + sameShadow = (style.TextShadow.Color == _CurrentViewLink->getShadowColor()); + sameShadow = sameShadow && (style.TextShadow.Outline == _CurrentViewLink->getShadowOutline()); + sameShadow = sameShadow && (style.TextShadow.X == sx) && (style.TextShadow.Y == sy); } // Compatible with current parameters ? if (!skipLine && sameShadow && - (_Style.TextColor == _CurrentViewLink->getColor()) && - (_Style.FontFamily == _CurrentViewLink->getFontName()) && - (_Style.FontSize == (uint)_CurrentViewLink->getFontSize()) && - (_Style.Underlined == _CurrentViewLink->getUnderlined()) && - (_Style.StrikeThrough == _CurrentViewLink->getStrikeThrough()) && + (style.TextColor == _CurrentViewLink->getColor()) && + (style.FontFamily == _CurrentViewLink->getFontName()) && + (style.FontSize == (uint)_CurrentViewLink->getFontSize()) && + (style.Underlined == _CurrentViewLink->getUnderlined()) && + (style.StrikeThrough == _CurrentViewLink->getStrikeThrough()) && (embolden == _CurrentViewLink->getEmbolden()) && - (_Style.FontOblique == _CurrentViewLink->getOblique()) && + (style.FontOblique == _CurrentViewLink->getOblique()) && (getLink() == _CurrentViewLink->Link) && - (_Style.GlobalColor == _CurrentViewLink->getModulateGlobalColor())) + (style.GlobalColor == _CurrentViewLink->getModulateGlobalColor())) { // Concat the text _CurrentViewLink->setText(_CurrentViewLink->getText()+tmpStr); @@ -4574,7 +4201,7 @@ namespace NLGUI ctrlButton->setDefaultContextHelp(ucstring::makeFromUtf8(getLinkTitle())); ctrlButton->setText(tmpStr); - setTextButtonStyle(ctrlButton, _Style); + setTextButtonStyle(ctrlButton, style); } getParagraph()->addChild (buttonGroup); paragraphChange (); @@ -4597,10 +4224,10 @@ namespace NLGUI } } newLink->setText(tmpStr); - newLink->setMultiLineSpace((uint)((float)(_Style.FontSize)*LineSpaceFontFactor)); + newLink->setMultiLineSpace((uint)((float)(style.FontSize)*LineSpaceFontFactor)); newLink->setMultiLine(true); - newLink->setModulateGlobalColor(_Style.GlobalColor); - setTextStyle(newLink, _Style); + newLink->setModulateGlobalColor(style.GlobalColor); + setTextStyle(newLink, style); // newLink->setLineAtBottom (true); registerAnchor(newLink); @@ -4705,22 +4332,23 @@ namespace NLGUI // No more text in this text view _CurrentViewLink = NULL; + CStyleParams &style = _Style.Current; { // override cols/rows values from style - if (_Style.Width > 0) cols = _Style.Width / _Style.FontSize; - if (_Style.Height > 0) rows = _Style.Height / _Style.FontSize; + if (style.Width > 0) cols = style.Width / style.FontSize; + if (style.Height > 0) rows = style.Height / style.FontSize; // Not added ? std::vector > templateParams; - templateParams.push_back (std::pair ("w", toString (cols*_Style.FontSize))); + templateParams.push_back (std::pair ("w", toString (cols*style.FontSize))); templateParams.push_back (std::pair ("id", name)); templateParams.push_back (std::pair ("prompt", "")); templateParams.push_back (std::pair ("multiline", multiLine?"true":"false")); - templateParams.push_back (std::pair ("fontsize", toString (_Style.FontSize))); - templateParams.push_back (std::pair ("color", _Style.TextColor.toString())); - if (_Style.FontWeight >= FONT_WEIGHT_BOLD) + templateParams.push_back (std::pair ("fontsize", toString (style.FontSize))); + templateParams.push_back (std::pair ("color", style.TextColor.toString())); + if (style.FontWeight >= FONT_WEIGHT_BOLD) templateParams.push_back (std::pair ("fontweight", "bold")); - if (_Style.FontOblique) + if (style.FontOblique) templateParams.push_back (std::pair ("fontstyle", "oblique")); if (multiLine) templateParams.push_back (std::pair ("multi_min_line", toString(rows))); @@ -4729,13 +4357,13 @@ namespace NLGUI templateParams.push_back (std::pair ("enter_recover_focus", "false")); if (maxlength > 0) templateParams.push_back (std::pair ("max_num_chars", toString(maxlength))); - templateParams.push_back (std::pair ("shadow", toString(_Style.TextShadow.Enabled))); - if (_Style.TextShadow.Enabled) + templateParams.push_back (std::pair ("shadow", toString(style.TextShadow.Enabled))); + if (style.TextShadow.Enabled) { - templateParams.push_back (std::pair ("shadow_x", toString(_Style.TextShadow.X))); - templateParams.push_back (std::pair ("shadow_y", toString(_Style.TextShadow.Y))); - templateParams.push_back (std::pair ("shadow_color", _Style.TextShadow.Color.toString())); - templateParams.push_back (std::pair ("shadow_outline", toString(_Style.TextShadow.Outline))); + templateParams.push_back (std::pair ("shadow_x", toString(style.TextShadow.X))); + templateParams.push_back (std::pair ("shadow_y", toString(style.TextShadow.Y))); + templateParams.push_back (std::pair ("shadow_color", style.TextShadow.Color.toString())); + templateParams.push_back (std::pair ("shadow_outline", toString(style.TextShadow.Outline))); } CInterfaceGroup *textArea = CWidgetManager::getInstance()->getParser()->createGroupInstance (templateName.c_str(), @@ -4749,13 +4377,13 @@ namespace NLGUI if (eb) { eb->setInputString(decodeHTMLEntities(content)); - if (_Style.BackgroundColor.A > 0) + if (style.BackgroundColor.A > 0) { CViewBitmap *bg = dynamic_cast(eb->getView("bg")); if (bg) { bg->setTexture("blank.tga"); - bg->setColor(_Style.BackgroundColor); + bg->setColor(style.BackgroundColor); } } } @@ -6411,423 +6039,11 @@ namespace NLGUI // *************************************************************************** void CGroupHTML::resetCssStyle() { - _StyleDefault = CStyleParams(); - _StyleDefault.TextColor = TextColor; - _StyleDefault.FontSize = TextFontSize; - _StyleDefault.BackgroundColor = BgColor; - - _Style = _StyleDefault; - _StyleParams.clear(); - } - - // *************************************************************************** - // CGroupHTML::CStyleParams style; - // style.FontSize; // font-size: 10px; - // style.TextColor; // color: #ABCDEF; - // style.Underlined; // text-decoration: underline; text-decoration-line: underline; - // style.StrikeThrough; // text-decoration: line-through; text-decoration-line: line-through; - void CGroupHTML::getStyleParams(const std::string &styleString, CStyleParams &style, const CStyleParams ¤t) - { - float tmpf; - TStyle styles = parseStyle(styleString); - TStyle::iterator it; - - // first pass: get font-size for 'em' sizes - for (it=styles.begin(); it != styles.end(); ++it) - { - if (it->first == "font") - { - if (it->second == "inherit") - { - style.FontSize = current.FontSize; - style.FontFamily = current.FontFamily; - style.FontWeight = current.FontWeight; - style.FontOblique = current.FontOblique; - } - } - else - if (it->first == "font-size") - { - if (it->second == "inherit") - { - style.FontSize = current.FontSize; - } - else - { - std::string unit; - if (getCssLength(tmpf, unit, it->second.c_str())) - { - if (unit == "rem") - style.FontSize = _StyleDefault.FontSize * tmpf; - else if (unit == "em") - style.FontSize = current.FontSize * tmpf; - else if (unit == "pt") - style.FontSize = tmpf / 0.75f; - else if (unit == "%") - style.FontSize = current.FontSize * tmpf / 100.f; - else - style.FontSize = tmpf; - } - } - } - } - - // second pass: rest of style - for (it=styles.begin(); it != styles.end(); ++it) - { - if (it->first == "border") - { - sint32 b; - if (it->second == "none") - style.BorderWidth = 0; - else - if (fromString(it->second, b)) - style.BorderWidth = b; - } - else - if (it->first == "font-style") - { - if (it->second == "inherit") - style.FontOblique = current.FontOblique; - else - if (it->second == "italic" || it->second == "oblique") - style.FontOblique = true; - } - else - if (it->first == "font-family") - { - if (it->second == "inherit") - style.FontFamily = current.FontFamily; - else - style.FontFamily = it->second; - } - else - if (it->first == "font-weight") - { - // https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight - uint weight = 400; - if (it->second == "inherit") - weight = current.FontWeight; - else - if (it->second == "normal") - weight = 400; - else - if (it->second == "bold") - weight = 700; - else - if (it->second == "lighter") - { - const uint lighter[] = {100, 100, 100, 100, 100, 400, 400, 700, 700}; - uint index = current.FontWeight / 100 - 1; - clamp(index, 1u, 9u); - weight = lighter[index-1]; - } - else - if (it->second == "bolder") - { - const uint bolder[] = {400, 400, 400, 700, 700, 900, 900, 900, 900}; - uint index = current.FontWeight / 100 + 1; - clamp(index, 1u, 9u); - weight = bolder[index-1]; - } - else - if (fromString(it->second, weight)) - { - weight = (weight / 100); - clamp(weight, 1u, 9u); - weight *= 100; - } - style.FontWeight = weight; - } - else - if (it->first == "color") - if (it->second == "inherit") - style.TextColor = current.TextColor; - else - scanHTMLColor(it->second.c_str(), style.TextColor); - else - if (it->first == "text-decoration" || it->first == "text-decoration-line") - { - std::string prop(toLower(it->second)); - style.Underlined = (prop.find("underline") != std::string::npos); - style.StrikeThrough = (prop.find("line-through") != std::string::npos); - } - else - if (it->first == "text-stroke" || it->first == "-webkit-text-stroke") - { - // text-stroke: length || color - bool success = false; - uint px = 0; - CRGBA color; - std::vector parts; - NLMISC::splitString(it->second, " ", parts); - if (parts.size() == 1) - { - success = scanCssLength(parts[0], px); - if (!success) - success = scanHTMLColor(parts[0].c_str(), color); - } - else if (parts.size() == 2) - { - success = scanCssLength(parts[0], px); - if (success) - success = scanHTMLColor(parts[1].c_str(), color); - else - { - success = scanHTMLColor(parts[0].c_str(), color); - success = success && scanCssLength(parts[1], px); - } - } - - // do not disable shadow if one is already set - if (success) - { - style.TextShadow.Enabled = (px > 0); - style.TextShadow.Color = color; - style.TextShadow.X = px; - style.TextShadow.Y = px; - style.TextShadow.Outline = true; - } - } - else - if (it->first == "text-shadow") - { - if (it->second == "none") - style.TextShadow = STextShadow(false); - else - if (it->second == "inherit") - style.TextShadow = current.TextShadow; - else - { - // text-shadow: offset-x offset-y | blur | #color - // text-shadow: #color | offset-x offset-y - bool success = true; - std::string prop(it->second); - size_t pos; - pos = prop.find_first_of(",\n\r"); - if (pos != std::string::npos) - prop = prop.substr(0, pos); - - std::vector parts; - NLMISC::splitString(prop, " ", parts); - switch(parts.size()) - { - case 1: - { - success = scanHTMLColor(it->second.c_str(), style.TextShadow.Color); - break; - } - // no case 2: - case 3: - { - if (!fromString(parts[0], style.TextShadow.X)) - { - success = scanHTMLColor(parts[0].c_str(), style.TextShadow.Color); - success = success && fromString(parts[1], style.TextShadow.X); - success = success && fromString(parts[2], style.TextShadow.Y); - } - else - { - success = fromString(parts[1], style.TextShadow.Y); - success = success && scanHTMLColor(parts[2].c_str(), style.TextShadow.Color); - } - break; - } - case 4: - { - if (!fromString(parts[0], style.TextShadow.X)) - { - success = scanHTMLColor(parts[0].c_str(), style.TextShadow.Color); - success = success && fromString(parts[1], style.TextShadow.X); - success = success && fromString(parts[2], style.TextShadow.Y); - // ignore blur [3] - } - else - { - success = fromString(parts[0], style.TextShadow.X); - success = success && fromString(parts[1], style.TextShadow.Y); - // ignore blur [2] - success = success && scanHTMLColor(parts[3].c_str(), style.TextShadow.Color); - } - break; - } - default: - { - // unsupported rule - break; - } - } - - style.TextShadow.Enabled = success; - } - } - else - if (it->first == "width") - { - std::string unit; - if (getCssLength(tmpf, unit, it->second.c_str())) - { - if (unit == "rem") - style.Width = tmpf * _StyleDefault.FontSize; - else if (unit == "em") - style.Width = tmpf * style.FontSize; - else if (unit == "pt") - style.FontSize = tmpf / 0.75f; - else - style.Width = tmpf; - } - } - else - if (it->first == "height") - { - std::string unit; - if (getCssLength(tmpf, unit, it->second.c_str())) - { - if (unit == "rem") - style.Height = tmpf * _StyleDefault.FontSize; - else if (unit == "em") - style.Height = tmpf * style.FontSize; - else if (unit == "pt") - style.FontSize = tmpf / 0.75f; - else - style.Height = tmpf; - } - } - else - if (it->first == "max-width") - { - std::string unit; - if (getCssLength(tmpf, unit, it->second.c_str())) - { - if (unit == "rem") - style.MaxWidth = tmpf * _StyleDefault.FontSize; - else if (unit == "em") - style.MaxWidth = tmpf * style.FontSize; - else if (unit == "pt") - style.FontSize = tmpf / 0.75f; - else - style.MaxWidth = tmpf; - } - } - else - if (it->first == "max-height") - { - std::string unit; - if (getCssLength(tmpf, unit, it->second.c_str())) - { - if (unit == "rem") - style.MaxHeight = tmpf * _StyleDefault.FontSize; - else if (unit == "em") - style.MaxHeight = tmpf * style.FontSize; - else if (unit == "pt") - style.FontSize = tmpf / 0.75f; - else - style.MaxHeight = tmpf; - } - } - else - if (it->first == "-ryzom-modulate-color") - { - bool b; - if (it->second == "inherit") - style.GlobalColor = current.GlobalColor; - else - if (fromString(it->second, b)) - style.GlobalColor = b; - } - else - if (it->first == "background-color") - { - if (it->second == "inherit") - style.BackgroundColor = current.BackgroundColor; - else - scanHTMLColor(it->second.c_str(), style.BackgroundColor); - } - else - if (it->first == "-ryzom-background-color-over") - { - if (it->second == "inherit") - style.BackgroundColorOver = current.BackgroundColorOver; - else - scanHTMLColor(it->second.c_str(), style.BackgroundColorOver); - } - } - - // if outer element has underline set, then inner element cannot remove it - if (current.Underlined) - style.Underlined = current.Underlined; - - // if outer element has line-through set, then inner element cannot remove it - if (current.StrikeThrough) - style.StrikeThrough = current.StrikeThrough; - } - - // *************************************************************************** - void CGroupHTML::applyCssMinMax(sint32 &width, sint32 &height, sint32 minw, sint32 minh, sint32 maxw, sint32 maxh) - { - if (maxw <= 0) maxw = width; - if (maxh <= 0) maxh = height; - - maxw = std::max(minw, maxw); - maxh = std::max(minh, maxh); - - float ratio = (float) width / std::max(1, height); - if (width > maxw) - { - width = maxw; - height = std::max((sint32)(maxw /ratio), minh); - } - if (width < minw) - { - width = minw; - height = std::min((sint32)(minw / ratio), maxh); - } - if (height > maxh) - { - width = std::max((sint32)(maxh * ratio), minw); - height = maxh; - } - if (height < minh) - { - width = std::min((sint32)(minh * ratio), maxw); - height = minh; - } - if (width > maxw && height > maxh) - { - if (maxw/width <= maxh/height) - { - width = maxw; - height = std::max(minh, (sint32)(maxw / ratio)); - } - else - { - width = std::max(minw, (sint32)(maxh * ratio)); - height = maxh; - } - } - if (width < minw && height < minh) - { - if (minw / width <= minh / height) - { - width = std::min(maxw, (sint32)(minh * ratio)); - height = minh; - } - else - { - width = minw; - height = std::min(maxh, (sint32)(minw / ratio)); - } - } - if (width < minw && height > maxh) - { - width = minw; - height = maxh; - } - if (width > maxw && height < minh) - { - width = maxw; - height = minh; - } + _Style.reset(); + _Style.Root.TextColor = TextColor; + _Style.Root.FontSize = TextFontSize; + _Style.Root.BackgroundColor = BgColor; + _Style.Current = _Style.Root; } // *************************************************************************** diff --git a/code/nel/src/gui/libwww.cpp b/code/nel/src/gui/libwww.cpp index ca8920b14..50cac24bf 100644 --- a/code/nel/src/gui/libwww.cpp +++ b/code/nel/src/gui/libwww.cpp @@ -345,6 +345,368 @@ namespace NLGUI } } + static bool isHexa(char c) + { + return isdigit(c) || (tolower(c) >= 'a' && tolower(c) <= 'f'); + } + + static uint8 convertHexa(char c) + { + return (uint8) (tolower(c) - (isdigit(c) ? '0' : ('a' - 10))); + } + + // scan a color component, and return pointer to next position + static const char *scanColorComponent(const char *src, uint8 &intensity) + { + if (!src) return NULL; + if (!isHexa(*src)) return NULL; + uint8 value = convertHexa(*src++) << 4; + if (!isHexa(*src)) return NULL; + value += convertHexa(*src++); + intensity = value; + return src; + } + + static float hueToRgb(float m1, float m2, float h) + { + if (h < 0) h += 1.0f; + if (h > 1) h -= 1.0f; + if (h*6 < 1.0f) return m1 + (m2 - m1)*h*6; + if (h*2 < 1.0f) return m2; + if (h*3 < 2.0f) return m1 + (m2 - m1) * (2.0f/3.0f - h)*6; + return m1; + } + + static void hslToRgb(float h, float s, float l, CRGBA &result) + { + float m1, m2; + if (l <= 0.5f) + m2 = l * (s + 1.0f); + else + m2 = l + s - l * s; + m1 = l*2 - m2; + + result.R = 255 * hueToRgb(m1, m2, h + 1.0f/3.0f); + result.G = 255 * hueToRgb(m1, m2, h); + result.B = 255 * hueToRgb(m1, m2, h - 1.0f/3.0f); + result.A = 255; + } + + class CNameToCol + { + public: + const char *Name; + CRGBA Color; + CNameToCol(const char *name, CRGBA color) : Name(name), Color(color) {} + }; + + static CNameToCol htmlColorNameToRGBA[] = + { + CNameToCol("AliceBlue", CRGBA(0xF0, 0xF8, 0xFF)), + CNameToCol("AntiqueWhite", CRGBA(0xFA, 0xEB, 0xD7)), + CNameToCol("Aqua", CRGBA(0x00, 0xFF, 0xFF)), + CNameToCol("Aquamarine", CRGBA(0x7F, 0xFF, 0xD4)), + CNameToCol("Azure", CRGBA(0xF0, 0xFF, 0xFF)), + CNameToCol("Beige", CRGBA(0xF5, 0xF5, 0xDC)), + CNameToCol("Bisque", CRGBA(0xFF, 0xE4, 0xC4)), + CNameToCol("Black", CRGBA(0x00, 0x00, 0x00)), + CNameToCol("BlanchedAlmond", CRGBA(0xFF, 0xEB, 0xCD)), + CNameToCol("Blue", CRGBA(0x00, 0x00, 0xFF)), + CNameToCol("BlueViolet", CRGBA(0x8A, 0x2B, 0xE2)), + CNameToCol("Brown", CRGBA(0xA5, 0x2A, 0x2A)), + CNameToCol("BurlyWood", CRGBA(0xDE, 0xB8, 0x87)), + CNameToCol("CadetBlue", CRGBA(0x5F, 0x9E, 0xA0)), + CNameToCol("Chartreuse", CRGBA(0x7F, 0xFF, 0x00)), + CNameToCol("Chocolate", CRGBA(0xD2, 0x69, 0x1E)), + CNameToCol("Coral", CRGBA(0xFF, 0x7F, 0x50)), + CNameToCol("CornflowerBlue", CRGBA(0x64, 0x95, 0xED)), + CNameToCol("Cornsilk", CRGBA(0xFF, 0xF8, 0xDC)), + CNameToCol("Crimson", CRGBA(0xDC, 0x14, 0x3C)), + CNameToCol("Cyan", CRGBA(0x00, 0xFF, 0xFF)), + CNameToCol("DarkBlue", CRGBA(0x00, 0x00, 0x8B)), + CNameToCol("DarkCyan", CRGBA(0x00, 0x8B, 0x8B)), + CNameToCol("DarkGoldenRod", CRGBA(0xB8, 0x86, 0x0B)), + CNameToCol("DarkGray", CRGBA(0xA9, 0xA9, 0xA9)), + CNameToCol("DarkGreen", CRGBA(0x00, 0x64, 0x00)), + CNameToCol("DarkKhaki", CRGBA(0xBD, 0xB7, 0x6B)), + CNameToCol("DarkMagenta", CRGBA(0x8B, 0x00, 0x8B)), + CNameToCol("DarkOliveGreen", CRGBA(0x55, 0x6B, 0x2F)), + CNameToCol("Darkorange", CRGBA(0xFF, 0x8C, 0x00)), + CNameToCol("DarkOrchid", CRGBA(0x99, 0x32, 0xCC)), + CNameToCol("DarkRed", CRGBA(0x8B, 0x00, 0x00)), + CNameToCol("DarkSalmon", CRGBA(0xE9, 0x96, 0x7A)), + CNameToCol("DarkSeaGreen", CRGBA(0x8F, 0xBC, 0x8F)), + CNameToCol("DarkSlateBlue", CRGBA(0x48, 0x3D, 0x8B)), + CNameToCol("DarkSlateGray", CRGBA(0x2F, 0x4F, 0x4F)), + CNameToCol("DarkTurquoise", CRGBA(0x00, 0xCE, 0xD1)), + CNameToCol("DarkViolet", CRGBA(0x94, 0x00, 0xD3)), + CNameToCol("DeepPink", CRGBA(0xFF, 0x14, 0x93)), + CNameToCol("DeepSkyBlue", CRGBA(0x00, 0xBF, 0xFF)), + CNameToCol("DimGray", CRGBA(0x69, 0x69, 0x69)), + CNameToCol("DodgerBlue", CRGBA(0x1E, 0x90, 0xFF)), + CNameToCol("Feldspar", CRGBA(0xD1, 0x92, 0x75)), + CNameToCol("FireBrick", CRGBA(0xB2, 0x22, 0x22)), + CNameToCol("FloralWhite", CRGBA(0xFF, 0xFA, 0xF0)), + CNameToCol("ForestGreen", CRGBA(0x22, 0x8B, 0x22)), + CNameToCol("Fuchsia", CRGBA(0xFF, 0x00, 0xFF)), + CNameToCol("Gainsboro", CRGBA(0xDC, 0xDC, 0xDC)), + CNameToCol("GhostWhite", CRGBA(0xF8, 0xF8, 0xFF)), + CNameToCol("Gold", CRGBA(0xFF, 0xD7, 0x00)), + CNameToCol("GoldenRod", CRGBA(0xDA, 0xA5, 0x20)), + CNameToCol("Gray", CRGBA(0x80, 0x80, 0x80)), + CNameToCol("Green", CRGBA(0x00, 0x80, 0x00)), + CNameToCol("GreenYellow", CRGBA(0xAD, 0xFF, 0x2F)), + CNameToCol("HoneyDew", CRGBA(0xF0, 0xFF, 0xF0)), + CNameToCol("HotPink", CRGBA(0xFF, 0x69, 0xB4)), + CNameToCol("IndianRed ", CRGBA(0xCD, 0x5C, 0x5C)), + CNameToCol("Indigo ", CRGBA(0x4B, 0x00, 0x82)), + CNameToCol("Ivory", CRGBA(0xFF, 0xFF, 0xF0)), + CNameToCol("Khaki", CRGBA(0xF0, 0xE6, 0x8C)), + CNameToCol("Lavender", CRGBA(0xE6, 0xE6, 0xFA)), + CNameToCol("LavenderBlush", CRGBA(0xFF, 0xF0, 0xF5)), + CNameToCol("LawnGreen", CRGBA(0x7C, 0xFC, 0x00)), + CNameToCol("LemonChiffon", CRGBA(0xFF, 0xFA, 0xCD)), + CNameToCol("LightBlue", CRGBA(0xAD, 0xD8, 0xE6)), + CNameToCol("LightCoral", CRGBA(0xF0, 0x80, 0x80)), + CNameToCol("LightCyan", CRGBA(0xE0, 0xFF, 0xFF)), + CNameToCol("LightGoldenRodYellow", CRGBA(0xFA, 0xFA, 0xD2)), + CNameToCol("LightGrey", CRGBA(0xD3, 0xD3, 0xD3)), + CNameToCol("LightGreen", CRGBA(0x90, 0xEE, 0x90)), + CNameToCol("LightPink", CRGBA(0xFF, 0xB6, 0xC1)), + CNameToCol("LightSalmon", CRGBA(0xFF, 0xA0, 0x7A)), + CNameToCol("LightSeaGreen", CRGBA(0x20, 0xB2, 0xAA)), + CNameToCol("LightSkyBlue", CRGBA(0x87, 0xCE, 0xFA)), + CNameToCol("LightSlateBlue", CRGBA(0x84, 0x70, 0xFF)), + CNameToCol("LightSlateGray", CRGBA(0x77, 0x88, 0x99)), + CNameToCol("LightSteelBlue", CRGBA(0xB0, 0xC4, 0xDE)), + CNameToCol("LightYellow", CRGBA(0xFF, 0xFF, 0xE0)), + CNameToCol("Lime", CRGBA(0x00, 0xFF, 0x00)), + CNameToCol("LimeGreen", CRGBA(0x32, 0xCD, 0x32)), + CNameToCol("Linen", CRGBA(0xFA, 0xF0, 0xE6)), + CNameToCol("Magenta", CRGBA(0xFF, 0x00, 0xFF)), + CNameToCol("Maroon", CRGBA(0x80, 0x00, 0x00)), + CNameToCol("MediumAquaMarine", CRGBA(0x66, 0xCD, 0xAA)), + CNameToCol("MediumBlue", CRGBA(0x00, 0x00, 0xCD)), + CNameToCol("MediumOrchid", CRGBA(0xBA, 0x55, 0xD3)), + CNameToCol("MediumPurple", CRGBA(0x93, 0x70, 0xD8)), + CNameToCol("MediumSeaGreen", CRGBA(0x3C, 0xB3, 0x71)), + CNameToCol("MediumSlateBlue", CRGBA(0x7B, 0x68, 0xEE)), + CNameToCol("MediumSpringGreen", CRGBA(0x00, 0xFA, 0x9A)), + CNameToCol("MediumTurquoise", CRGBA(0x48, 0xD1, 0xCC)), + CNameToCol("MediumVioletRed", CRGBA(0xC7, 0x15, 0x85)), + CNameToCol("MidnightBlue", CRGBA(0x19, 0x19, 0x70)), + CNameToCol("MintCream", CRGBA(0xF5, 0xFF, 0xFA)), + CNameToCol("MistyRose", CRGBA(0xFF, 0xE4, 0xE1)), + CNameToCol("Moccasin", CRGBA(0xFF, 0xE4, 0xB5)), + CNameToCol("NavajoWhite", CRGBA(0xFF, 0xDE, 0xAD)), + CNameToCol("Navy", CRGBA(0x00, 0x00, 0x80)), + CNameToCol("OldLace", CRGBA(0xFD, 0xF5, 0xE6)), + CNameToCol("Olive", CRGBA(0x80, 0x80, 0x00)), + CNameToCol("OliveDrab", CRGBA(0x6B, 0x8E, 0x23)), + CNameToCol("Orange", CRGBA(0xFF, 0xA5, 0x00)), + CNameToCol("OrangeRed", CRGBA(0xFF, 0x45, 0x00)), + CNameToCol("Orchid", CRGBA(0xDA, 0x70, 0xD6)), + CNameToCol("PaleGoldenRod", CRGBA(0xEE, 0xE8, 0xAA)), + CNameToCol("PaleGreen", CRGBA(0x98, 0xFB, 0x98)), + CNameToCol("PaleTurquoise", CRGBA(0xAF, 0xEE, 0xEE)), + CNameToCol("PaleVioletRed", CRGBA(0xD8, 0x70, 0x93)), + CNameToCol("PapayaWhip", CRGBA(0xFF, 0xEF, 0xD5)), + CNameToCol("PeachPuff", CRGBA(0xFF, 0xDA, 0xB9)), + CNameToCol("Peru", CRGBA(0xCD, 0x85, 0x3F)), + CNameToCol("Pink", CRGBA(0xFF, 0xC0, 0xCB)), + CNameToCol("Plum", CRGBA(0xDD, 0xA0, 0xDD)), + CNameToCol("PowderBlue", CRGBA(0xB0, 0xE0, 0xE6)), + CNameToCol("Purple", CRGBA(0x80, 0x00, 0x80)), + CNameToCol("Red", CRGBA(0xFF, 0x00, 0x00)), + CNameToCol("RosyBrown", CRGBA(0xBC, 0x8F, 0x8F)), + CNameToCol("RoyalBlue", CRGBA(0x41, 0x69, 0xE1)), + CNameToCol("SaddleBrown", CRGBA(0x8B, 0x45, 0x13)), + CNameToCol("Salmon", CRGBA(0xFA, 0x80, 0x72)), + CNameToCol("SandyBrown", CRGBA(0xF4, 0xA4, 0x60)), + CNameToCol("SeaGreen", CRGBA(0x2E, 0x8B, 0x57)), + CNameToCol("SeaShell", CRGBA(0xFF, 0xF5, 0xEE)), + CNameToCol("Sienna", CRGBA(0xA0, 0x52, 0x2D)), + CNameToCol("Silver", CRGBA(0xC0, 0xC0, 0xC0)), + CNameToCol("SkyBlue", CRGBA(0x87, 0xCE, 0xEB)), + CNameToCol("SlateBlue", CRGBA(0x6A, 0x5A, 0xCD)), + CNameToCol("SlateGray", CRGBA(0x70, 0x80, 0x90)), + CNameToCol("Snow", CRGBA(0xFF, 0xFA, 0xFA)), + CNameToCol("SpringGreen", CRGBA(0x00, 0xFF, 0x7F)), + CNameToCol("SteelBlue", CRGBA(0x46, 0x82, 0xB4)), + CNameToCol("Tan", CRGBA(0xD2, 0xB4, 0x8C)), + CNameToCol("Teal", CRGBA(0x00, 0x80, 0x80)), + CNameToCol("Thistle", CRGBA(0xD8, 0xBF, 0xD8)), + CNameToCol("Tomato", CRGBA(0xFF, 0x63, 0x47)), + CNameToCol("Turquoise", CRGBA(0x40, 0xE0, 0xD0)), + CNameToCol("Violet", CRGBA(0xEE, 0x82, 0xEE)), + CNameToCol("VioletRed", CRGBA(0xD0, 0x20, 0x90)), + CNameToCol("Wheat", CRGBA(0xF5, 0xDE, 0xB3)), + CNameToCol("White", CRGBA(0xFF, 0xFF, 0xFF)), + CNameToCol("WhiteSmoke", CRGBA(0xF5, 0xF5, 0xF5)), + CNameToCol("Yellow", CRGBA(0xFF, 0xFF, 0x00)), + CNameToCol("YellowGreen", CRGBA(0x9A, 0xCD, 0x32)) + }; + + // scan a color from a HTML form (#rrggbb format) + bool scanHTMLColor(const char *src, CRGBA &dest) + { + if (!src || *src == '\0') return false; + if (*src == '#') + { + ++src; + if (strlen(src) == 3 || strlen(src) == 4) + { + bool hasAlpha = (strlen(src) == 4); + // check RGB for valid hex + if (isHexa(src[0]) && isHexa(src[1]) && isHexa(src[2])) + { + // check optional A for valid hex + if (hasAlpha && !isHexa(src[3])) return false; + + dest.R = convertHexa(src[0]); + dest.G = convertHexa(src[1]); + dest.B = convertHexa(src[2]); + + dest.R = dest.R << 4 | dest.R; + dest.G = dest.G << 4 | dest.G; + dest.B = dest.B << 4 | dest.B; + + if (hasAlpha) + { + dest.A = convertHexa(src[3]); + dest.A = dest.A << 4 | dest.A; + } + else + dest.A = 255; + + return true; + } + + return false; + } + + CRGBA result; + src = scanColorComponent(src, result.R); if (!src) return false; + src = scanColorComponent(src, result.G); if (!src) return false; + src = scanColorComponent(src, result.B); if (!src) return false; + src = scanColorComponent(src, result.A); + if (!src) + { + // Alpha is optional + result.A = 255; + } + dest = result; + return true; + } + + if (strnicmp(src, "rgb(", 4) == 0 || strnicmp(src, "rgba(", 5) == 0) + { + src += 4; + if (*src == '(') src++; + + std::vector parts; + NLMISC::splitString(src, ",", parts); + if (parts.size() >= 3) + { + CRGBA result; + sint tmpv; + float tmpf; + + // R + if (getPercentage(tmpv, tmpf, parts[0].c_str())) tmpv = 255 * tmpf; + clamp(tmpv, 0, 255); + result.R = tmpv; + + // G + if (getPercentage(tmpv, tmpf, parts[1].c_str())) tmpv = 255 * tmpf; + clamp(tmpv, 0, 255); + result.G = tmpv; + + // B + if (getPercentage(tmpv, tmpf, parts[2].c_str())) tmpv = 255 * tmpf; + clamp(tmpv, 0, 255); + result.B = tmpv; + + // A + if (parts.size() == 4) + { + if (!fromString(parts[3], tmpf)) return false; + if (parts[3].find_first_of("%") != std::string::npos) + tmpf /= 100; + + tmpv = 255 * tmpf; + clamp(tmpv, 0, 255); + result.A = tmpv; + } + else + result.A = 255; + + dest = result; + return true; + } + + return false; + } + + if (strnicmp(src, "hsl(", 4) == 0 || strnicmp(src, "hsla(", 5) == 0) + { + src += 4; + if (*src == '(') src++; + + std::vector parts; + NLMISC::splitString(src, ",", parts); + if (parts.size() >= 3) + { + sint tmpv; + float h, s, l; + // hue + if (!fromString(parts[0], tmpv)) return false; + tmpv = ((tmpv % 360) + 360) % 360; + h = (float) tmpv / 360.0f; + + // saturation + if (!getPercentage(tmpv, s, parts[1].c_str())) return false; + clamp(s, 0.0f, 1.0f); + + // lightness + if (!getPercentage(tmpv, l, parts[2].c_str())) return false; + clamp(l, 0.0f, 1.0f); + + CRGBA result; + hslToRgb(h, s, l, result); + + // A + if (parts.size() == 4) + { + float tmpf; + if (!fromString(parts[3], tmpf)) return false; + if (parts[3].find_first_of("%") != std::string::npos) + tmpf /= 100; + clamp(tmpf, 0.0f, 1.0f); + result.A = 255 * tmpf; + } + + dest = result; + return true; + } + + return false; + } + + { + // slow but should suffice for now + for(uint k = 0; k < sizeofarray(htmlColorNameToRGBA); ++k) + { + if (nlstricmp(src, htmlColorNameToRGBA[k].Name) == 0) + { + dest = htmlColorNameToRGBA[k].Color; + return true; + } + } + return false; + } + } + // *************************************************************************** CRGBA getColor (const char *color) From aede4dbab7b9871772ed01ede1b361c2f6af174b Mon Sep 17 00:00:00 2001 From: Nimetu Date: Mon, 29 Apr 2019 15:03:55 +0300 Subject: [PATCH 06/75] Added: relative/absolute font size values for css --HG-- branch : develop --- code/nel/src/gui/css_style.cpp | 35 ++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/code/nel/src/gui/css_style.cpp b/code/nel/src/gui/css_style.cpp index 9d4b665bb..35d28717e 100644 --- a/code/nel/src/gui/css_style.cpp +++ b/code/nel/src/gui/css_style.cpp @@ -114,6 +114,41 @@ namespace NLGUI { style.FontSize = current.FontSize; } + else if (it->second == "x-small") + { + style.FontSize = 10; // 62.5% + } + else if (it->second == "small") + { + style.FontSize = 13; // 80%; + } + else if (it->second == "medium") + { + style.FontSize = 16; // 100%; + } + else if (it->second == "large") + { + style.FontSize = 18; // 112.5% + } + else if (it->second == "x-large") + { + style.FontSize = 24; // 150% + } + else if (it->second == "xx-large") + { + style.FontSize = 32; // 200%; + } + else if (it->second == "smaller") + { + if (style.FontSize < 5) + style.FontSize = 3; + else + style.FontSize -= 2; + } + else if (it->second == "larger") + { + style.FontSize += 2; + } else { std::string unit; From 9587e9bcefbe4182d542e1e163ade517b25da705 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Mon, 29 Apr 2019 15:03:55 +0300 Subject: [PATCH 07/75] Added: transparent, currentcolor values for background-color --HG-- branch : develop --- code/nel/src/gui/css_style.cpp | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/code/nel/src/gui/css_style.cpp b/code/nel/src/gui/css_style.cpp index 35d28717e..8fc1207d2 100644 --- a/code/nel/src/gui/css_style.cpp +++ b/code/nel/src/gui/css_style.cpp @@ -95,8 +95,21 @@ namespace NLGUI TStyle::iterator it; // first pass: get font-size for 'em' sizes + // get TextColor value used as 'currentcolor' for (it=styles.begin(); it != styles.end(); ++it) { + if (it->first == "color") + { + if (it->second == "inherit") + { + style.TextColor = current.TextColor; + } + else + { + scanHTMLColor(it->second.c_str(), style.TextColor); + } + } + else if (it->first == "font") { if (it->second == "inherit") @@ -237,12 +250,6 @@ namespace NLGUI style.FontWeight = weight; } else - if (it->first == "color") - if (it->second == "inherit") - style.TextColor = current.TextColor; - else - scanHTMLColor(it->second.c_str(), style.TextColor); - else if (it->first == "text-decoration" || it->first == "text-decoration-line") { std::string prop(toLower(it->second)); @@ -437,6 +444,10 @@ namespace NLGUI { if (it->second == "inherit") style.BackgroundColor = current.BackgroundColor; + else if (it->second == "transparent") + style.BackgroundColor = CRGBA(0, 0, 0, 0); + else if (it->second == "currentcolor") + style.BackgroundColorOver = style.TextColor; else scanHTMLColor(it->second.c_str(), style.BackgroundColor); } @@ -445,6 +456,10 @@ namespace NLGUI { if (it->second == "inherit") style.BackgroundColorOver = current.BackgroundColorOver; + else if (it->second == "transparent") + style.BackgroundColorOver = CRGBA(0, 0, 0, 0); + else if (it->second == "currentcolor") + style.BackgroundColorOver = style.TextColor; else scanHTMLColor(it->second.c_str(), style.BackgroundColorOver); } From fb54672815daa322bcb8b76aed120ef3decb8769 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Fri, 5 Apr 2019 21:57:42 +0300 Subject: [PATCH 08/75] Changed: Implement HTML renderer with CSS styling --HG-- branch : develop --- code/nel/include/nel/gui/css_parser.h | 113 +- code/nel/include/nel/gui/css_selector.h | 107 + code/nel/include/nel/gui/css_style.h | 90 +- code/nel/include/nel/gui/group_html.h | 125 +- code/nel/include/nel/gui/html_element.h | 86 + code/nel/include/nel/gui/html_parser.h | 20 +- code/nel/include/nel/gui/libwww.h | 3 + code/nel/include/nel/misc/common.h | 11 + code/nel/src/gui/css_parser.cpp | 658 +++++ code/nel/src/gui/css_selector.cpp | 314 +++ code/nel/src/gui/css_style.cpp | 494 +++- code/nel/src/gui/group_html.cpp | 2438 +++++++++++++++-- code/nel/src/gui/html_element.cpp | 168 ++ code/nel/src/gui/html_parser.cpp | 188 +- code/nel/src/gui/libwww.cpp | 10 + code/nel/src/gui/libwww_types.cpp | 2 + .../src/interface_v3/group_quick_help.cpp | 58 +- .../src/interface_v3/group_quick_help.h | 3 +- 18 files changed, 4587 insertions(+), 301 deletions(-) create mode 100644 code/nel/include/nel/gui/css_selector.h create mode 100644 code/nel/include/nel/gui/html_element.h create mode 100644 code/nel/src/gui/css_selector.cpp create mode 100644 code/nel/src/gui/html_element.cpp diff --git a/code/nel/include/nel/gui/css_parser.h b/code/nel/include/nel/gui/css_parser.h index cb4cea62e..cfaf03caa 100644 --- a/code/nel/include/nel/gui/css_parser.h +++ b/code/nel/include/nel/gui/css_parser.h @@ -19,6 +19,7 @@ #include "nel/misc/types_nl.h" #include "nel/gui/css_style.h" +#include "nel/gui/css_selector.h" namespace NLGUI { @@ -31,8 +32,118 @@ namespace NLGUI 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 index 2a854a6d9..dea4a1f43 100644 --- a/code/nel/include/nel/gui/css_style.h +++ b/code/nel/include/nel/gui/css_style.h @@ -19,9 +19,12 @@ #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; /** @@ -44,7 +47,7 @@ namespace NLGUI sint32 X; sint32 Y; NLMISC::CRGBA Color; - }; + }; public: CStyleParams () : FontFamily(""), TextColor(255,255,255,255), TextShadow() { @@ -62,6 +65,19 @@ namespace NLGUI 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; @@ -78,11 +94,26 @@ namespace NLGUI 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; @@ -90,18 +121,37 @@ namespace NLGUI // 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 + // 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; + + // 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) @@ -109,15 +159,29 @@ namespace NLGUI 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(); @@ -125,16 +189,32 @@ namespace NLGUI } } - // apply style string to this.Root + // apply style to this.Root void applyRootStyle(const std::string &styleString); + void applyRootStyle(const TStyle &styleRules); - // apply style string to this.Current + // 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 d8935f431..6a8760533 100644 --- a/code/nel/include/nel/gui/group_html.h +++ b/code/nel/include/nel/gui/group_html.h @@ -24,6 +24,7 @@ #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 @@ -76,7 +77,7 @@ namespace NLGUI static SWebOptions options; // ImageDownload system - enum TDataType {ImgType= 0, BnpType}; + enum TDataType {ImgType= 0, BnpType, StylesheetType}; enum TImageType {NormalImage=0, OverImage}; // Constructor @@ -97,6 +98,9 @@ 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 bool parseHtml(const std::string &htmlString); @@ -273,16 +277,10 @@ namespace NLGUI 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); @@ -296,6 +294,9 @@ namespace NLGUI // 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(); @@ -326,7 +327,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); @@ -365,6 +366,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 @@ -484,6 +493,11 @@ namespace NLGUI // 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; @@ -722,6 +736,12 @@ namespace NLGUI private: friend class CHtmlParser; + // TODO: beginElement is overwritten in client quick help class, merge it here? + void beginElementDeprecated(uint element_number, const std::vector &present, const std::vector &value); + void endElementDeprecated(uint element_number); + + // move src->Children into CurrentHtmlElement.parent.children element + void spliceFragment(std::list::iterator src); // decode all HTML entities static ucstring decodeHTMLEntities(const ucstring &str); @@ -764,6 +784,8 @@ namespace NLGUI int RunningCurls; bool startCurlDownload(CDataDownload &download); + void finishCurlDownload(CDataDownload &download); + void pumpCurlDownloads(); void initImageDownload(); void checkImageDownload(); @@ -782,11 +804,94 @@ 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); + void releaseDownloads(); void checkDownloads(); // 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); + + // 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 index 132c4ac88..760640234 100644 --- a/code/nel/include/nel/gui/html_parser.h +++ b/code/nel/include/nel/gui/html_parser.h @@ -21,7 +21,7 @@ namespace NLGUI { - class CGroupHTML; + class CHtmlElement; /** * \brief HTML parsing @@ -31,21 +31,21 @@ namespace NLGUI class CHtmlParser { public: - CHtmlParser(CGroupHTML *group) : _GroupHtml(group) - {} + bool parseHtml(std::string htmlString) const; - bool parseHtml(std::string htmlString); + // 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; + + //