starmath/inc/error.hxx | 3 starmath/inc/parse.hxx | 3 starmath/inc/strings.hrc | 5 starmath/inc/strings.hxx | 2 starmath/inc/token.hxx | 28 - starmath/source/ElementsDockingWindow.cxx | 7 starmath/source/node.cxx | 41 -- starmath/source/parse.cxx | 601 +++++++++++++++++++----------- starmath/source/visitors.cxx | 34 + 9 files changed, 463 insertions(+), 261 deletions(-)
New commits: commit 351f620baa64ecabd4f7f93ec0139724766c7c59 Author: Dante DM <dante19031...@gmail.com> AuthorDate: Wed Oct 21 15:43:30 2020 +0200 Commit: Noel Grandin <noel.gran...@collabora.co.uk> CommitDate: Tue Nov 3 20:57:12 2020 +0100 Added hexadecimal number and color support for starmath. Adds hidden command on guy hex number wich allows to use numbers of base 16 and also 0-9-A-Z. Added support for custom RGB colors on hexadecimal on starmath via command color hex colornumber. Improved RGB color handle on starmath. Changed the way the color is handled on starmath. Colors keywords won't give errors. They have been moved to an independent tokens list so starmath will load tokens faster. Changed the way the font size is handeled on starmath. This won't change anything, just related with the structural change. Implemented premature support for rgba colors on math. This change only adds the possibility on the parser, node and node visitors. For now end-user can not access it since in a future there'll be work to do on the renderer to add full support. Added hex entrie on the docking window. Changes made on Color.hxx, will save some nanoseconds on build. If you are interested on allowing rgba and do the job on the renderer (and all the other stuff than there are a lot of .GetRGBColor()), you may find usefull color hex colnum. Since transparency setting is ignored, the hexadecimal color has hidden support for it since did not instore the max value (255 + 255*256 + 255*256*256) and everything is loaded into the sal_uInt32. Change-Id: Iafb38b142fffa329ca468e3d62643154fcdd2bbf Reviewed-on: https://gerrit.libreoffice.org/c/core/+/104630 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk> diff --git a/starmath/inc/error.hxx b/starmath/inc/error.hxx index a05123d6e080..d8179da593d5 100644 --- a/starmath/inc/error.hxx +++ b/starmath/inc/error.hxx @@ -39,7 +39,8 @@ enum class SmParseError FontExpected, SizeExpected, DoubleAlign, - DoubleSubsupscript + DoubleSubsupscript, + NumberExpected }; diff --git a/starmath/inc/parse.hxx b/starmath/inc/parse.hxx index 519a90041f65..4f1e3024ccb3 100644 --- a/starmath/inc/parse.hxx +++ b/starmath/inc/parse.hxx @@ -83,6 +83,8 @@ class SmParser SmParser& operator=(const SmParser&) = delete; void NextToken(); + void NextTokenColor(); + void NextTokenFontSize(); sal_Int32 GetTokenIndex() const { return m_nTokenIndex; } void Replace( sal_Int32 nPos, sal_Int32 nLen, const OUString &rText ); @@ -140,7 +142,6 @@ public: const SmErrorDesc* NextError(); const SmErrorDesc* PrevError(); const SmErrorDesc* GetError(); - static const SmTokenTableEntry* GetTokenTableEntry( const OUString &rName ); const std::set< OUString >& GetUsedSymbols() const { return m_aUsedSymbols; } }; diff --git a/starmath/inc/strings.hrc b/starmath/inc/strings.hrc index 64144759f5cc..50adc4a3e042 100644 --- a/starmath/inc/strings.hrc +++ b/starmath/inc/strings.hrc @@ -195,6 +195,8 @@ #define RID_COLORX_TEAL_HELP NC_("RID_COLORX_TEAL_HELP", "Color Teal" ) #define RID_COLORX_YELLOW_HELP NC_("RID_COLORX_YELLOW_HELP", "Color Yellow" ) #define RID_COLORX_RGB_HELP NC_("RID_COLORX_RGB_HELP", "Color RGB" ) +#define RID_COLORX_RGBA_HELP NC_("RID_COLORX_RGBA_HELP", "Color RGBA" ) +#define RID_COLORX_HEX_HELP NC_("RID_COLORX_HEX_HELP", "Color hexadecimal" ) #define RID_LRGROUPX_HELP NC_("RID_LRGROUPX_HELP", "Group Brackets" ) #define RID_LRPARENTX_HELP NC_("RID_LRPARENTX_HELP", "Round Brackets" ) #define RID_LRBRACKETX_HELP NC_("RID_LRBRACKETX_HELP", "Square Brackets" ) @@ -317,6 +319,8 @@ #define STR_TEAL NC_("STR_TEAL", "teal" ) #define STR_YELLOW NC_("STR_YELLOW", "yellow" ) #define STR_RGB NC_("STR_RGB", "rgb" ) +#define STR_RGBA NC_("STR_RGBA", "rgba" ) +#define STR_HEX NC_("STR_HEX", "hex" ) #define STR_HIDE NC_("STR_HIDE", "hide" ) #define STR_SIZE NC_("STR_SIZE", "size" ) #define STR_FONT NC_("STR_FONT", "font" ) @@ -339,6 +343,7 @@ #define RID_ERR_SIZEEXPECTED NC_("RID_ERR_SIZEEXPECTED", "'size' followed by an unexpected token" ) #define RID_ERR_DOUBLEALIGN NC_("RID_ERR_DOUBLEALIGN", "Double aligning is not allowed" ) #define RID_ERR_DOUBLESUBSUPSCRIPT NC_("RID_ERR_DOUBLESUBSUPSCRIPT", "Double sub/superscripts is not allowed" ) +#define RID_ERR_NUMBEREXPECTED NC_("RID_ERR_NUMBEREXPECTED", "Expected number" ) #define RID_ERR_POUNDEXPECTED NC_("RID_ERR_POUNDEXPECTED", "'#' expected" ) #define RID_ERR_COLOREXPECTED NC_("RID_ERR_COLOREXPECTED", "Color required" ) #define RID_ERR_RIGHTEXPECTED NC_("RID_ERR_RIGHTEXPECTED", "'RIGHT' expected" ) diff --git a/starmath/inc/strings.hxx b/starmath/inc/strings.hxx index fb00ac2f4782..2daf463afd25 100644 --- a/starmath/inc/strings.hxx +++ b/starmath/inc/strings.hxx @@ -188,6 +188,8 @@ #define RID_COLORX_TEAL "color teal {<?>} " #define RID_COLORX_YELLOW "color yellow {<?>} " #define RID_COLORX_RGB "color rgb 0 0 0 {<?>} " +#define RID_COLORX_RGBA "color rgba 0 0 0 0 {<?>} " +#define RID_COLORX_HEX "color hex 000000 {<?>} " #define RID_LRGROUPX "{<?>} " #define RID_LRPARENTX "(<?>) " #define RID_LRBRACKETX "[<?>] " diff --git a/starmath/inc/token.hxx b/starmath/inc/token.hxx index 1403e96987a2..a58e28d42be8 100644 --- a/starmath/inc/token.hxx +++ b/starmath/inc/token.hxx @@ -64,14 +64,12 @@ enum SmTokenType TDOTSDIAG, TDOTSUP, TDOTSDOWN, TACUTE, TBAR, TBREVE, TCHECK, TCIRCLE, TDOT, TDDOT, TDDDOT, TGRAVE, THAT, TTILDE, TVEC, - THARPOON, TUNDERLINE, TOVERLINE, TOVERSTRIKE, TITALIC, TNITALIC, TBOLD, TNBOLD, TPHANTOM, TFONT, TSIZE, TCOLOR, TALIGNL, TALIGNC, TALIGNR, TLEFT, TRIGHT, TLANGLE, TLBRACE, TLLINE, TLDLINE, TLCEIL, TLFLOOR, TNONE, TMLINE, TRANGLE, TRBRACE, TRLINE, TRDLINE, TRCEIL, TRFLOOR, - TSIN, TCOS, TTAN, TCOT, TFUNC, TSTACK, TMATRIX, TDPOUND, TPLACE, TTEXT, TNUMBER, TCHARACTER, TIDENT, TNEQ, TEQUIV, TDEF, TPROP, TSIM, TSIMEQ, @@ -81,12 +79,7 @@ enum SmTokenType TODIVIDE, TTRANSL, TTRANSR, TIINT, TIIINT, TLINT, TLLINT, TLLLINT, TPROD, TCOPROD, TFORALL, TEXISTS, TNOTEXISTS, TLIM, TNABLA, - TTOWARD, TSINH, TCOSH, TTANH, TCOTH, - TASIN, TACOS, TATAN, TLN, TLOG, - TUOPER, TBOPER, TBLACK, TWHITE, TRED, - TGREEN, TBLUE, TCYAN, TMAGENTA, TYELLOW, - TFIXED, TSANS, TSERIF, TASINH, - TACOSH, TATANH, TACOTH, TACOT, TEXP, + TUOPER, TBOPER, TFIXED, TSANS, TSERIF, TCDOT, TODOT, TLESLANT, TGESLANT, TNSUBSET, TNSUPSET, TNSUBSETEQ, TNSUPSETEQ, TPARTIAL, TNEG, TNI, TBACKEPSILON, TALEPH, TIM, TRE, @@ -96,13 +89,22 @@ enum SmTokenType TLAMBDABAR, TLEFTARROW, TRIGHTARROW, TUPARROW, TDOWNARROW, TDIVIDES, TSETN, TSETZ, TSETQ, TSETR, TSETC, TWIDEVEC, TWIDEHARPOON, TWIDETILDE, - TWIDEHAT, TWIDESLASH, TWIDEBACKSLASH, TLDBRACKET, TRDBRACKET, TNOSPACE, TUNKNOWN, TPRECEDES, TSUCCEEDS, TPRECEDESEQUAL, TSUCCEEDSEQUAL, - TPRECEDESEQUIV, TSUCCEEDSEQUIV, TNOTPRECEDES, TNOTSUCCEEDS, TSILVER, - TGRAY, TMAROON, TPURPLE, TLIME, TOLIVE, - TNAVY, TTEAL, TAQUA, TFUCHSIA, TINTD, - TRGB, TLAPLACE, TFOURIER + TPRECEDESEQUIV, TSUCCEEDSEQUIV, TNOTPRECEDES, TNOTSUCCEEDS, THARPOON, + TINTD, TLAPLACE, TFOURIER, TTOWARD, TWIDEHAT, + // Function + TFUNC, TLN, TLOG, TEXP, // Exp - Log + TSIN, TCOS, TTAN, TCOT, // Trigo + TSINH, TCOSH, TTANH, TCOTH, // Trigo hyperbolic + TASIN, TACOS, TATAN, TACOT, // Arctrigo + TASINH, TACOSH, TATANH, TACOTH, // Arctrigo hyperbolic + // Color + TRGB, TRGBA, THEX, + TAQUA, TBLACK, TBLUE, TCYAN, TFUCHSIA, + TGRAY, TGREEN, TLIME, TMAGENTA, TMAROON, + TNAVY, TOLIVE, TPURPLE, TRED, TSILVER, + TTEAL, TWHITE, TYELLOW }; struct SmToken diff --git a/starmath/source/ElementsDockingWindow.cxx b/starmath/source/ElementsDockingWindow.cxx index 516f424f0107..053c7e04dc06 100644 --- a/starmath/source/ElementsDockingWindow.cxx +++ b/starmath/source/ElementsDockingWindow.cxx @@ -189,7 +189,8 @@ const SmElementDescr SmElementsControl::m_aAttributesList[] = {RID_COLORX_LIME, RID_COLORX_LIME_HELP}, {RID_COLORX_MAROON, RID_COLORX_MAROON_HELP}, {RID_COLORX_NAVY, RID_COLORX_NAVY_HELP}, {RID_COLORX_OLIVE, RID_COLORX_OLIVE_HELP}, {RID_COLORX_PURPLE, RID_COLORX_PURPLE_HELP}, {RID_COLORX_SILVER, RID_COLORX_SILVER_HELP}, - {RID_COLORX_TEAL, RID_COLORX_TEAL_HELP},{RID_COLORX_RGB, RID_COLORX_RGB_HELP} + {RID_COLORX_TEAL, RID_COLORX_TEAL_HELP},{RID_COLORX_RGB, RID_COLORX_RGB_HELP}, + {RID_COLORX_HEX, RID_COLORX_HEX_HELP} }; const SmElementDescr SmElementsControl::m_aBracketsList[] = @@ -924,6 +925,10 @@ void SmElementsControl::addElements(const SmElementDescr aElementsArray[], sal_u addElement(aParser, "color teal { \"" + SmResId(STR_TEAL) + "\" }", aElement, SmResId(pElementHelp)); else if (aElement == RID_COLORX_RGB) addElement(aParser, "color rgb 0 0 0 { \"" + SmResId(STR_RGB) + "\" }", aElement, SmResId(pElementHelp)); + else if (aElement == RID_COLORX_RGBA) + addElement(aParser, "color rgba 0 0 0 0 { \"" + SmResId(STR_RGBA) + "\" }", aElement, SmResId(pElementHelp)); + else if (aElement == RID_COLORX_HEX) + addElement(aParser, "color hex 000000 { \"" + SmResId(STR_HEX) + "\" }", aElement, SmResId(pElementHelp)); else if (aElement == RID_ALIGNLX) addElement(aParser, "\"" + SmResId(STR_ALIGN_LEFT) + "\"", aElement, SmResId(pElementHelp)); else if (aElement == RID_ALIGNCX) diff --git a/starmath/source/node.cxx b/starmath/source/node.cxx index e252b83ee308..957c91cb33c6 100644 --- a/starmath/source/node.cxx +++ b/starmath/source/node.cxx @@ -1607,8 +1607,7 @@ void SmFontNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat) { SmNode *pNode = GetSubNode(1); assert(pNode); - sal_Int32 nc; - Color col_perso_rgb_color = COL_AUTO; + sal_uInt32 nc; switch (GetToken().eType) { case TSIZE : @@ -1646,13 +1645,10 @@ void SmFontNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat) case TAQUA : SetColor(COL_LIGHTCYAN); break; case TFUCHSIA : SetColor(COL_LIGHTMAGENTA); break; case TRGB : - nc = GetToken().aText.toInt32(); - col_perso_rgb_color.SetBlue(nc % 256); - nc /= 256; - col_perso_rgb_color.SetGreen(nc % 256); - nc /= 256; - col_perso_rgb_color.SetRed(nc % 256); - SetColor(col_perso_rgb_color); + case TRGBA : + case THEX : + nc = GetToken().aText.toUInt32(); + SetColor(Color(nc)); break; default: @@ -1855,28 +1851,13 @@ void SmTextNode::GetAccessibleText( OUStringBuffer &rText ) const void SmTextNode::AdjustFontDesc() { - if (GetToken().eType == TTEXT) - mnFontDesc = FNT_TEXT; - else if(GetToken().eType == TFUNC) - mnFontDesc = FNT_FUNCTION; + if (GetToken().nGroup == TG::Function) mnFontDesc = FNT_FUNCTION; + else if (GetToken().eType == TTEXT) mnFontDesc = FNT_TEXT; else { - const SmTokenTableEntry *pEntry = SmParser::GetTokenTableEntry( maText ); - if (pEntry && pEntry->nGroup == TG::Function) { - GetToken().eType = pEntry->eType; - mnFontDesc = FNT_FUNCTION; - } else { - sal_Unicode firstChar = maText[0]; - if( ('0' <= firstChar && firstChar <= '9') || firstChar == '.' || firstChar == ',') { - mnFontDesc = FNT_NUMBER; - GetToken().eType = TNUMBER; - } else if (maText.getLength() > 1) { - mnFontDesc = FNT_VARIABLE; - GetToken().eType = TIDENT; - } else { - mnFontDesc = FNT_VARIABLE; - GetToken().eType = TCHARACTER; - } - } + sal_Unicode firstChar = maText[0]; + if( ('0' <= firstChar && firstChar <= '9') || firstChar == '.' || firstChar == ',') + mnFontDesc = FNT_NUMBER; + else mnFontDesc = FNT_VARIABLE; } } diff --git a/starmath/source/parse.cxx b/starmath/source/parse.cxx index a5872f9e9118..6d7e1891b762 100644 --- a/starmath/source/parse.cxx +++ b/starmath/source/parse.cxx @@ -78,7 +78,6 @@ const SmTokenTableEntry aTokenTable[] = { "alignt", TALIGNC, '\0', TG::Align, 0}, { "and", TAND, MS_AND, TG::Product, 0}, { "approx", TAPPROX, MS_APPROX, TG::Relation, 0}, - { "aqua", TAQUA, '\0', TG::Color, 0}, { "arccos", TACOS, '\0', TG::Function, 5}, { "arccot", TACOT, '\0', TG::Function, 5}, { "arcosh", TACOSH, '\0', TG::Function, 5 }, @@ -90,8 +89,6 @@ const SmTokenTableEntry aTokenTable[] = { "backepsilon" , TBACKEPSILON, MS_BACKEPSILON, TG::Standalone, 5}, { "bar", TBAR, MS_BAR, TG::Attribute, 5}, { "binom", TBINOM, '\0', TG::NONE, 5 }, - { "black", TBLACK, '\0', TG::Color, 0}, - { "blue", TBLUE, '\0', TG::Color, 0}, { "bold", TBOLD, '\0', TG::FontAttr, 5}, { "boper", TBOPER, '\0', TG::Product, 0}, { "breve", TBREVE, MS_BREVE, TG::Attribute, 5}, @@ -108,7 +105,6 @@ const SmTokenTableEntry aTokenTable[] = { "coth", TCOTH, '\0', TG::Function, 5}, { "csub", TCSUB, '\0', TG::Power, 0}, { "csup", TCSUP, '\0', TG::Power, 0}, - { "cyan", TCYAN, '\0', TG::Color, 0}, { "dddot", TDDDOT, MS_DDDOT, TG::Attribute, 5}, { "ddot", TDDOT, MS_DDOT, TG::Attribute, 5}, { "def", TDEF, MS_DEF, TG::Relation, 0}, @@ -135,14 +131,11 @@ const SmTokenTableEntry aTokenTable[] = { "forall", TFORALL, MS_FORALL, TG::Standalone, 5}, { "fourier", TFOURIER, MS_FOURIER, TG::Standalone, 5}, { "from", TFROM, '\0', TG::Limit, 0}, - { "fuchsia", TFUCHSIA, '\0', TG::Color, 0}, { "func", TFUNC, '\0', TG::Function, 5}, { "ge", TGE, MS_GE, TG::Relation, 0}, { "geslant", TGESLANT, MS_GESLANT, TG::Relation, 0 }, { "gg", TGG, MS_GG, TG::Relation, 0}, { "grave", TGRAVE, MS_GRAVE, TG::Attribute, 5}, - { "gray", TGRAY, '\0', TG::Color, 0}, - { "green", TGREEN, '\0', TG::Color, 0}, { "gt", TGT, MS_GT, TG::Relation, 0}, { "harpoon", THARPOON, MS_HARPOON, TG::Attribute, 5}, { "hat", THAT, MS_HAT, TG::Attribute, 5}, @@ -171,7 +164,6 @@ const SmTokenTableEntry aTokenTable[] = { "leslant", TLESLANT, MS_LESLANT, TG::Relation, 0 }, { "lfloor", TLFLOOR, MS_LFLOOR, TG::LBrace, 5}, { "lim", TLIM, '\0', TG::Oper, 5}, - { "lime", TLIME, '\0', TG::Color, 0}, { "liminf", TLIMINF, '\0', TG::Oper, 5}, { "limsup", TLIMSUP, '\0', TG::Oper, 5}, { "lint", TLINT, MS_LINT, TG::Oper, 5}, @@ -184,13 +176,10 @@ const SmTokenTableEntry aTokenTable[] = { "lsub", TLSUB, '\0', TG::Power, 0}, { "lsup", TLSUP, '\0', TG::Power, 0}, { "lt", TLT, MS_LT, TG::Relation, 0}, - { "magenta", TMAGENTA, '\0', TG::Color, 0}, - { "maroon", TMAROON, '\0', TG::Color, 0}, { "matrix", TMATRIX, '\0', TG::NONE, 5}, { "minusplus", TMINUSPLUS, MS_MINUSPLUS, TG::UnOper | TG::Sum, 5}, { "mline", TMLINE, MS_VERTLINE, TG::NONE, 0}, //! not in TG::RBrace, Level 0 { "nabla", TNABLA, MS_NABLA, TG::Standalone, 5}, - { "navy", TNAVY, '\0', TG::Color, 0}, { "nbold", TNBOLD, '\0', TG::FontAttr, 5}, { "ndivides", TNDIVIDES, MS_NDIVIDES, TG::Relation, 0}, { "neg", TNEG, MS_NEG, TG::UnOper, 5 }, @@ -211,7 +200,6 @@ const SmTokenTableEntry aTokenTable[] = { "nsupseteq", TNSUPSETEQ, MS_NSUPSETEQ, TG::Relation, 0 }, { "odivide", TODIVIDE, MS_ODIVIDE, TG::Product, 0}, { "odot", TODOT, MS_ODOT, TG::Product, 0}, - { "olive", TOLIVE, '\0', TG::Color, 0}, { "ominus", TOMINUS, MS_OMINUS, TG::Sum, 0}, { "oper", TOPER, '\0', TG::Oper, 5}, { "oplus", TOPLUS, MS_OPLUS, TG::Sum, 0}, @@ -232,16 +220,13 @@ const SmTokenTableEntry aTokenTable[] = { "precsim", TPRECEDESEQUIV, MS_PRECEDESEQUIV, TG::Relation, 0 }, { "prod", TPROD, MS_PROD, TG::Oper, 5}, { "prop", TPROP, MS_PROP, TG::Relation, 0}, - { "purple", TPURPLE, '\0', TG::Color, 0}, { "rangle", TRANGLE, MS_RMATHANGLE, TG::RBrace, 0}, //! 0 to terminate expression { "rbrace", TRBRACE, MS_RBRACE, TG::RBrace, 0}, { "rceil", TRCEIL, MS_RCEIL, TG::RBrace, 0}, { "rdbracket", TRDBRACKET, MS_RDBRACKET, TG::RBrace, 0}, { "rdline", TRDLINE, MS_DVERTLINE, TG::RBrace, 0}, { "re" , TRE, MS_RE, TG::Standalone, 5 }, - { "red", TRED, '\0', TG::Color, 0}, { "rfloor", TRFLOOR, MS_RFLOOR, TG::RBrace, 0}, //! 0 to terminate expression - { "rgb", TRGB, '\0', TG::Color, 0}, { "right", TRIGHT, '\0', TG::NONE, 0}, { "rightarrow" , TRIGHTARROW, MS_RIGHTARROW, TG::Standalone, 5}, { "rline", TRLINE, MS_VERTLINE, TG::RBrace, 0}, //! 0 to terminate expression @@ -255,7 +240,6 @@ const SmTokenTableEntry aTokenTable[] = { "setQ" , TSETQ, MS_SETQ, TG::Standalone, 5}, { "setR" , TSETR, MS_SETR, TG::Standalone, 5}, { "setZ" , TSETZ, MS_SETZ, TG::Standalone, 5}, - { "silver", TSILVER, '\0', TG::Color, 0}, { "sim", TSIM, MS_SIM, TG::Relation, 0}, { "simeq", TSIMEQ, MS_SIMEQ, TG::Relation, 0}, { "sin", TSIN, '\0', TG::Function, 5}, @@ -276,7 +260,6 @@ const SmTokenTableEntry aTokenTable[] = { "supseteq", TSUPSETEQ, MS_SUPSETEQ, TG::Relation, 0}, { "tan", TTAN, '\0', TG::Function, 5}, { "tanh", TTANH, '\0', TG::Function, 5}, - { "teal", TTEAL, '\0', TG::Color, 0}, { "tilde", TTILDE, MS_TILDE, TG::Attribute, 5}, { "times", TTIMES, MS_TIMES, TG::Product, 0}, { "to", TTO, '\0', TG::Limit, 0}, @@ -289,59 +272,103 @@ const SmTokenTableEntry aTokenTable[] = { "uoper", TUOPER, '\0', TG::UnOper, 5}, { "uparrow" , TUPARROW, MS_UPARROW, TG::Standalone, 5}, { "vec", TVEC, MS_VEC, TG::Attribute, 5}, - { "white", TWHITE, '\0', TG::Color, 0}, { "widebslash", TWIDEBACKSLASH, MS_BACKSLASH, TG::Product, 0 }, { "wideharpoon", TWIDEHARPOON, MS_HARPOON, TG::Attribute, 5}, { "widehat", TWIDEHAT, MS_HAT, TG::Attribute, 5}, { "wideslash", TWIDESLASH, MS_SLASH, TG::Product, 0 }, { "widetilde", TWIDETILDE, MS_TILDE, TG::Attribute, 5}, { "widevec", TWIDEVEC, MS_VEC, TG::Attribute, 5}, - { "wp" , TWP, MS_WP, TG::Standalone, 5}, - { "yellow", TYELLOW, '\0', TG::Color, 0} + { "wp" , TWP, MS_WP, TG::Standalone, 5} }; -//Checks if keyword is in the list by SmTokenTableEntry. -#if !defined NDEBUG -static bool sortCompare(const SmTokenTableEntry & lhs, const SmTokenTableEntry & rhs) +//Definition of color keywords +const SmTokenTableEntry aColorTokenTable[] = { - return OUString::createFromAscii(lhs.pIdent).compareToIgnoreAsciiCase(OUString::createFromAscii(rhs.pIdent)) < 0; -} -#endif + { "aqua", TAQUA, '\0', TG::Color, 0}, + { "black", TBLACK, '\0', TG::Color, 0}, + { "blue", TBLUE, '\0', TG::Color, 0}, + { "cyan", TCYAN, '\0', TG::Color, 0}, + { "fuchsia", TFUCHSIA, '\0', TG::Color, 0}, + { "gray", TGRAY, '\0', TG::Color, 0}, + { "green", TGREEN, '\0', TG::Color, 0}, + { "hex" , THEX, '\0', TG::Color, 0}, + { "lime", TLIME, '\0', TG::Color, 0}, + { "magenta", TMAGENTA, '\0', TG::Color, 0}, + { "maroon", TMAROON, '\0', TG::Color, 0}, + { "navy", TNAVY, '\0', TG::Color, 0}, + { "olive", TOLIVE, '\0', TG::Color, 0}, + { "purple", TPURPLE, '\0', TG::Color, 0}, + { "red", TRED, '\0', TG::Color, 0}, + { "rgb", TRGB, '\0', TG::Color, 0}, + //{ "rgba", TRGBA, '\0', TG::Color, 0}, + { "silver", TSILVER, '\0', TG::Color, 0}, + { "teal", TTEAL, '\0', TG::Color, 0}, + { "white", TWHITE, '\0', TG::Color, 0}, + { "yellow", TYELLOW, '\0', TG::Color, 0} +}; + +// First character may be any alphabetic +const sal_Int32 coStartFlags = KParseTokens::ANY_LETTER | KParseTokens::IGNORE_LEADING_WS; + +// Continuing characters may be any alphabetic +const sal_Int32 coContFlags = (coStartFlags & ~KParseTokens::IGNORE_LEADING_WS) + | KParseTokens::TWO_DOUBLE_QUOTES_BREAK_STRING; +// First character for numbers, may be any numeric or dot +const sal_Int32 coNumStartFlags = KParseTokens::ASC_DIGIT | KParseTokens::ASC_DOT + | KParseTokens::IGNORE_LEADING_WS; +// Continuing characters for numbers, may be any numeric or dot or comma. +// tdf#127873: additionally accept ',' comma group separator as too many +// existing documents unwittingly may have used that as decimal separator +// in such locales (though it never was as this is always the en-US locale +// and the group separator is only parsed away). +const sal_Int32 coNumContFlags = (coNumStartFlags & ~KParseTokens::IGNORE_LEADING_WS) + | KParseTokens::GROUP_SEPARATOR_IN_NUMBER; +// First character for numbers hexadecimal +const sal_Int32 coNum16StartFlags = KParseTokens::ASC_DIGIT | KParseTokens::ASC_UPALPHA + | KParseTokens::IGNORE_LEADING_WS; + +// Continuing characters for numbers hexadecimal +const sal_Int32 coNum16ContFlags = (coNum16StartFlags & ~KParseTokens::IGNORE_LEADING_WS); +// user-defined char continuing characters may be any alphanumeric or dot. +const sal_Int32 coUserDefinedCharContFlags = KParseTokens::ANY_LETTER_OR_NUMBER + | KParseTokens::ASC_DOT + | KParseTokens::TWO_DOUBLE_QUOTES_BREAK_STRING; //Checks if keyword is in the list. -static bool findCompare(const SmTokenTableEntry & lhs, const OUString & s) +static inline bool findCompare(const SmTokenTableEntry & lhs, const OUString & s) { return s.compareToIgnoreAsciiCaseAscii(lhs.pIdent) > 0; } //Returns the SmTokenTableEntry for a keyword -const SmTokenTableEntry * SmParser::GetTokenTableEntry( const OUString &rName ) +static const SmTokenTableEntry * GetTokenTableEntry( const OUString &rName ) { - static bool bSortKeyWords = false; // Flag: RTF-token table has been sorted. - if( !bSortKeyWords ) //First time sorts it. - { - assert( std::is_sorted( std::begin(aTokenTable), std::end(aTokenTable), sortCompare ) ); - bSortKeyWords = true; - } - if (rName.isEmpty())return nullptr; //avoid null pointer exceptions - //Looks for the first keyword after or equal to rName in alphabetical order. - auto findIter = std::lower_bound( std::begin(aTokenTable), std::end(aTokenTable), rName, findCompare ); - if ( findIter != std::end(aTokenTable) && rName.equalsIgnoreAsciiCaseAscii( findIter->pIdent ))return &*findIter; //check is equal - + auto findIter = std::lower_bound( std::begin(aTokenTable), + std::end(aTokenTable), rName, findCompare ); + if ( findIter != std::end(aTokenTable) && rName.equalsIgnoreAsciiCaseAscii( findIter->pIdent )) + return &*findIter; //check is equal return nullptr; //not found } -namespace { - -bool IsDelimiter( const OUString &rTxt, sal_Int32 nPos ) - // returns 'true' iff cChar is '\0' or a delimiter +//Returns the SmTokenTableEntry for a keyword +static const SmTokenTableEntry * GetColorTokenTableEntry( const OUString &rName ) { - assert(nPos <= rTxt.getLength()); //index out of range + if (rName.isEmpty())return nullptr; //avoid null pointer exceptions + //Looks for the first keyword after or equal to rName in alphabetical order. + auto findIter = std::lower_bound( std::begin(aColorTokenTable), + std::end(aColorTokenTable), rName, findCompare ); + if ( findIter != std::end(aColorTokenTable) + && rName.equalsIgnoreAsciiCaseAscii( findIter->pIdent )) + return &*findIter; //check is equal + return nullptr; //not found +} +static bool IsDelimiter( const OUString &rTxt, sal_Int32 nPos ) +{ // returns 'true' iff cChar is '\0' or a delimiter + assert(nPos <= rTxt.getLength()); //index out of range if (nPos == rTxt.getLength())return true; //This is EOF - sal_Unicode cChar = rTxt[nPos]; // check if 'cChar' is in the delimiter table @@ -364,7 +391,42 @@ bool IsDelimiter( const OUString &rTxt, sal_Int32 nPos ) nTypJp == css::i18n::UnicodeType::CONTROL); } -}//end namespace +// checks number used as arguments in Math formulas (e.g. 'size' command) +// Format: no negative numbers, must start with a digit, no exponent notation, ... +static bool lcl_IsNumber(const OUString& rText) +{ + bool bPoint = false; + const sal_Unicode* pBuffer = rText.getStr(); + for(sal_Int32 nPos = 0; nPos < rText.getLength(); nPos++, pBuffer++) + { + const sal_Unicode cChar = *pBuffer; + if(cChar == '.') + { + if(bPoint) return false; + else bPoint = true; + } + else if ( !rtl::isAsciiDigit( cChar ) ) return false; + } + return true; +} +// checks number used as arguments in Math formulas (e.g. 'size' command) +// Format: no negative numbers, must start with a digit, no exponent notation, ... +static bool lcl_IsNotWholeNumber(const OUString& rText) +{ + const sal_Unicode* pBuffer = rText.getStr(); + for(sal_Int32 nPos = 0; nPos < rText.getLength(); nPos++, pBuffer++) + if ( !rtl::isAsciiDigit( *pBuffer ) ) return true; + return false; +} +// checks hex number used as arguments in Math formulas (e.g. 'hex' command) +// Format: no negative numbers, must start with a digit, no exponent notation, ... +static bool lcl_IsNotWholeNumber16(const OUString& rText) +{ + const sal_Unicode* pBuffer = rText.getStr(); + for(sal_Int32 nPos = 0; nPos < rText.getLength(); nPos++, pBuffer++) + if ( !rtl::isAsciiCanonicHexDigit( *pBuffer ) ) return true; + return false; +} //Text replace onto m_aBufferString void SmParser::Replace( sal_Int32 nPos, sal_Int32 nLen, const OUString &rText ) @@ -379,36 +441,6 @@ void SmParser::Replace( sal_Int32 nPos, sal_Int32 nLen, const OUString &rText ) void SmParser::NextToken() //Central part of the parser { - // First character may be any alphabetic - static const sal_Int32 coStartFlags = - KParseTokens::ANY_LETTER | - KParseTokens::IGNORE_LEADING_WS; - - // Continuing characters may be any alphabetic - static const sal_Int32 coContFlags = - (coStartFlags & ~KParseTokens::IGNORE_LEADING_WS) - | KParseTokens::TWO_DOUBLE_QUOTES_BREAK_STRING; - - // user-defined char continuing characters may be any alphanumeric or dot. - static const sal_Int32 coUserDefinedCharContFlags = - KParseTokens::ANY_LETTER_OR_NUMBER | - KParseTokens::ASC_DOT | - KParseTokens::TWO_DOUBLE_QUOTES_BREAK_STRING; - - // First character for numbers, may be any numeric or dot - static const sal_Int32 coNumStartFlags = - KParseTokens::ASC_DIGIT | - KParseTokens::ASC_DOT | - KParseTokens::IGNORE_LEADING_WS; - - // Continuing characters for numbers, may be any numeric or dot. - // tdf#127873: additionally accept ',' comma group separator as too many - // existing documents unwittingly may have used that as decimal separator - // in such locales (though it never was as this is always the en-US locale - // and the group separator is only parsed away). - static const sal_Int32 coNumContFlags = - (coNumStartFlags & ~KParseTokens::IGNORE_LEADING_WS) | - KParseTokens::GROUP_SEPARATOR_IN_NUMBER; sal_Int32 nBufLen = m_aBufferString.getLength(); ParseResult aRes; @@ -979,6 +1011,186 @@ void SmParser::NextToken() //Central part of the parser m_nBufferIndex = aRes.EndPos; } +void SmParser::NextTokenColor() +{ + + sal_Int32 nBufLen = m_aBufferString.getLength(); + ParseResult aRes; + sal_Int32 nRealStart; + bool bCont; + + do + { + // skip white spaces + while (UnicodeType::SPACE_SEPARATOR == + m_pSysCC->getType( m_aBufferString, m_nBufferIndex )) + ++m_nBufferIndex; + //parse, there are few options, so less strict. + aRes = m_pSysCC->parseAnyToken(m_aBufferString, m_nBufferIndex, + coStartFlags, "", coContFlags, ""); + nRealStart = m_nBufferIndex + aRes.LeadingWhiteSpace; + m_nBufferIndex = nRealStart; + bCont = false; + if ( aRes.TokenType == 0 && + nRealStart < nBufLen && + '\n' == m_aBufferString[ nRealStart ] ) + { + // keep data needed for tokens row and col entry up to date + ++m_nRow; + m_nBufferIndex = m_nColOff = nRealStart + 1; + bCont = true; + } + else if (aRes.TokenType & KParseType::ONE_SINGLE_CHAR) + { + if (nRealStart + 2 <= nBufLen && m_aBufferString.match("%%", nRealStart)) + { + //SkipComment + m_nBufferIndex = nRealStart + 2; + while (m_nBufferIndex < nBufLen && + '\n' != m_aBufferString[ m_nBufferIndex ]) + ++m_nBufferIndex; + bCont = true; + } + } + } while (bCont); + + // set index of current token + m_nTokenIndex = m_nBufferIndex; + m_aCurToken.nRow = m_nRow; + m_aCurToken.nCol = nRealStart - m_nColOff + 1; + if (nRealStart >= nBufLen) m_aCurToken.eType = TEND; + else if (aRes.TokenType & KParseType::IDENTNAME) + { + sal_Int32 n = aRes.EndPos - nRealStart; + assert(n >= 0); + OUString aName( m_aBufferString.copy( nRealStart, n ) ); + const SmTokenTableEntry *pEntry = GetColorTokenTableEntry( aName ); + if (pEntry) + { + m_aCurToken.eType = pEntry->eType; + m_aCurToken.cMathChar = pEntry->cMathChar; + m_aCurToken.nGroup = pEntry->nGroup; + m_aCurToken.nLevel = pEntry->nLevel; + m_aCurToken.aText = OUString::createFromAscii( pEntry->pIdent ); + } + else m_aCurToken.eType = TNONE; + } + else m_aCurToken.eType = TNONE; + if (TEND != m_aCurToken.eType) m_nBufferIndex = aRes.EndPos; +} + +void SmParser::NextTokenFontSize() +{ + + sal_Int32 nBufLen = m_aBufferString.getLength(); + ParseResult aRes; + sal_Int32 nRealStart; + bool bCont; + bool hex = false; + + do + { + // skip white spaces + while (UnicodeType::SPACE_SEPARATOR == + m_pSysCC->getType( m_aBufferString, m_nBufferIndex )) + ++m_nBufferIndex; + //hexadecimal parser + aRes = m_pSysCC->parseAnyToken(m_aBufferString, m_nBufferIndex, + coNum16StartFlags, ".", coNum16ContFlags, ".,"); + if (aRes.TokenType == 0) + { + // Try again with the default token parsing. + aRes = m_pSysCC->parseAnyToken(m_aBufferString, m_nBufferIndex, + coStartFlags, "", coContFlags, ""); + } + else hex = true; + nRealStart = m_nBufferIndex + aRes.LeadingWhiteSpace; + m_nBufferIndex = nRealStart; + bCont = false; + if ( aRes.TokenType == 0 && + nRealStart < nBufLen && + '\n' == m_aBufferString[ nRealStart ] ) + { + // keep data needed for tokens row and col entry up to date + ++m_nRow; + m_nBufferIndex = m_nColOff = nRealStart + 1; + bCont = true; + } + else if (aRes.TokenType & KParseType::ONE_SINGLE_CHAR) + { + if (nRealStart + 2 <= nBufLen && m_aBufferString.match("%%", nRealStart)) + { + //SkipComment + m_nBufferIndex = nRealStart + 2; + while (m_nBufferIndex < nBufLen && + '\n' != m_aBufferString[ m_nBufferIndex ]) + ++m_nBufferIndex; + bCont = true; + } + } + } while (bCont); + + // set index of current token + m_nTokenIndex = m_nBufferIndex; + m_aCurToken.nRow = m_nRow; + m_aCurToken.nCol = nRealStart - m_nColOff + 1; + if (nRealStart >= nBufLen) m_aCurToken.eType = TEND; + else if (aRes.TokenType & KParseType::ONE_SINGLE_CHAR) + { + if ( aRes.EndPos - nRealStart == 1 ) + { + switch ( m_aBufferString[ nRealStart ] ) + { + case '*': + m_aCurToken.eType = TMULTIPLY; + m_aCurToken.cMathChar = MS_MULTIPLY; + m_aCurToken.nGroup = TG::Product; + m_aCurToken.nLevel = 0; + m_aCurToken.aText = "*"; + break; + case '+': + m_aCurToken.eType = TPLUS; + m_aCurToken.cMathChar = MS_PLUS; + m_aCurToken.nGroup = TG::UnOper | TG::Sum; + m_aCurToken.nLevel = 5; + m_aCurToken.aText = "+"; + break; + case '-': + m_aCurToken.eType = TMINUS; + m_aCurToken.cMathChar = MS_MINUS; + m_aCurToken.nGroup = TG::UnOper | TG::Sum; + m_aCurToken.nLevel = 5; + m_aCurToken.aText = "-"; + break; + case '/': + m_aCurToken.eType = TDIVIDEBY; + m_aCurToken.cMathChar = MS_SLASH; + m_aCurToken.nGroup = TG::Product; + m_aCurToken.nLevel = 0; + m_aCurToken.aText = "/"; + break; + default: + m_aCurToken.eType = TNONE; + break; + } + } + else m_aCurToken.eType = TNONE; + } + else if(hex) + { + assert(aRes.EndPos > 0); + sal_Int32 n = aRes.EndPos - nRealStart; + assert(n >= 0); + m_aCurToken.eType = THEX; + m_aCurToken.cMathChar = '\0'; + m_aCurToken.nGroup = TG::NONE; + m_aCurToken.nLevel = 5; + m_aCurToken.aText = m_aBufferString.copy( nRealStart, n ); + } + else m_aCurToken.eType = TNONE; + if (TEND != m_aCurToken.eType) m_nBufferIndex = aRes.EndPos; +} + namespace { SmNodeArray buildNodeArray(std::vector<std::unique_ptr<SmNode>>& rSubNodes) @@ -991,6 +1203,7 @@ namespace } //end namespace // grammar +/*************************************************************************************************/ std::unique_ptr<SmTableNode> SmParser::DoTable() { @@ -1537,15 +1750,20 @@ std::unique_ptr<SmNode> SmParser::DoTerm(bool bGroupNumberIdent) case TMATRIX: return DoMatrix(); + case THEX: + NextTokenFontSize(); + if( m_aCurToken.eType == THEX ) + { + auto pTextNode = std::make_unique<SmTextNode>(m_aCurToken, FNT_NUMBER ); + NextToken(); + return pTextNode; + } + else return DoError(SmParseError::NumberExpected); default: - if (TokenInGroup(TG::LBrace)) - return DoBrace(); - if (TokenInGroup(TG::Oper)) - return DoOperator(); - if (TokenInGroup(TG::UnOper)) - return DoUnOper(); - if ( TokenInGroup(TG::Attribute) || - TokenInGroup(TG::FontAttr) ) + if (TokenInGroup(TG::LBrace)) return DoBrace(); + if (TokenInGroup(TG::Oper)) return DoOperator(); + if (TokenInGroup(TG::UnOper)) return DoUnOper(); + if ( TokenInGroup(TG::Attribute) || TokenInGroup(TG::FontAttr) ) { std::stack<std::unique_ptr<SmStructureNode>> aStack; bool bIsAttr; @@ -1862,51 +2080,76 @@ std::unique_ptr<SmStructureNode> SmParser::DoFontAttribut() std::unique_ptr<SmStructureNode> SmParser::DoColor() { DepthProtect aDepthGuard(m_nParseDepth); - if (aDepthGuard.TooDeep()) - throw std::range_error("parser depth limit"); + if (aDepthGuard.TooDeep()) throw std::range_error("parser depth limit"); assert(m_aCurToken.eType == TCOLOR); - - std::unique_ptr<SmStructureNode> xNode; - // last color rules, get that one + NextTokenColor(); SmToken aToken; - do - { - - NextToken(); - if (TokenInGroup(TG::Color)) + if (TokenInGroup(TG::Color)) + { + aToken = m_aCurToken; + if( m_aCurToken.eType == TRGB ) //loads r, g and b { - aToken = m_aCurToken; - if(m_aCurToken.eType==TRGB){ - SmToken r,g,b; - sal_Int32 nr, ng, nb, nc; - NextToken(); - if(m_aCurToken.eType!=TNUMBER)return DoError(SmParseError::ColorExpected); - r = m_aCurToken; - NextToken(); - if(m_aCurToken.eType!=TNUMBER)return DoError(SmParseError::ColorExpected); - g = m_aCurToken; - NextToken(); - if(m_aCurToken.eType!=TNUMBER)return DoError(SmParseError::ColorExpected); - b = m_aCurToken; - nr = r.aText.toInt32(); - if( nr < 0 || nr > 255 )return DoError(SmParseError::ColorExpected); - ng = g.aText.toInt32(); - if( ng < 0 || ng > 255 )return DoError(SmParseError::ColorExpected); - nb = b.aText.toInt32(); - if( nb < 0 || nb > 255 )return DoError(SmParseError::ColorExpected); - nc = nb + 256 * ( ng + nr*256 ); - aToken.aText = OUString::number(nc); - } - NextToken(); + sal_uInt32 nr, ng, nb, nc; + NextTokenFontSize(); + if( lcl_IsNotWholeNumber(m_aCurToken.aText) ) + return DoError(SmParseError::ColorExpected); + nr = m_aCurToken.aText.toUInt32(); + if( nr > 255 )return DoError(SmParseError::ColorExpected); + NextTokenFontSize(); + if( lcl_IsNotWholeNumber(m_aCurToken.aText) ) + return DoError(SmParseError::ColorExpected); + ng = m_aCurToken.aText.toUInt32(); + if( ng > 255 )return DoError(SmParseError::ColorExpected); + NextTokenFontSize(); + if( lcl_IsNotWholeNumber(m_aCurToken.aText) ) + return DoError(SmParseError::ColorExpected); + nb = m_aCurToken.aText.toUInt32(); + if( nb > 255 )return DoError(SmParseError::ColorExpected); + nc = nb | ng << 8 | nr << 16 | sal_uInt32(0) << 24; + aToken.aText = OUString::number(nc); } - else + else if( m_aCurToken.eType == TRGBA ) //loads r, g and b + { + sal_uInt32 nr, na, ng, nb, nc; + NextTokenFontSize(); + if( lcl_IsNotWholeNumber(m_aCurToken.aText) ) + return DoError(SmParseError::ColorExpected); + nr = m_aCurToken.aText.toUInt32(); + if( nr > 255 )return DoError(SmParseError::ColorExpected); + NextTokenFontSize(); + if( lcl_IsNotWholeNumber(m_aCurToken.aText) ) + return DoError(SmParseError::ColorExpected); + ng = m_aCurToken.aText.toUInt32(); + if( ng > 255 )return DoError(SmParseError::ColorExpected); + NextTokenFontSize(); + if( lcl_IsNotWholeNumber(m_aCurToken.aText) ) + return DoError(SmParseError::ColorExpected); + nb = m_aCurToken.aText.toUInt32(); + if( nb > 255 )return DoError(SmParseError::ColorExpected); + NextTokenFontSize(); + if( lcl_IsNotWholeNumber(m_aCurToken.aText) ) + return DoError(SmParseError::ColorExpected); + na = m_aCurToken.aText.toUInt32(); + if( na > 255 )return DoError(SmParseError::ColorExpected); + nc = nb | ng << 8 | nr << 16 | na << 24; + aToken.aText = OUString::number(nc); + } + else if( m_aCurToken.eType == THEX ) //loads hex code { - return DoError(SmParseError::ColorExpected); + sal_uInt32 nc; + NextTokenFontSize(); + if( lcl_IsNotWholeNumber16(m_aCurToken.aText) ) + return DoError(SmParseError::ColorExpected); + nc = m_aCurToken.aText.toUInt32(16); + aToken.aText = OUString::number(nc); } - } while (m_aCurToken.eType == TCOLOR); + NextToken(); + } + else return DoError(SmParseError::ColorExpected); + std::unique_ptr<SmStructureNode> xNode; xNode.reset(new SmFontNode(aToken)); return xNode; } @@ -1939,45 +2182,17 @@ std::unique_ptr<SmStructureNode> SmParser::DoFont() return xNode; } - -// gets number used as arguments in Math formulas (e.g. 'size' command) -// Format: no negative numbers, must start with a digit, no exponent notation, ... -static bool lcl_IsNumber(const OUString& rText) -{ - bool bPoint = false; - const sal_Unicode* pBuffer = rText.getStr(); - for(sal_Int32 nPos = 0; nPos < rText.getLength(); nPos++, pBuffer++) - { - const sal_Unicode cChar = *pBuffer; - if(cChar == '.') - { - if(bPoint) - return false; - else - bPoint = true; - } - else if ( !rtl::isAsciiDigit( cChar ) ) - return false; - } - return true; -} - std::unique_ptr<SmStructureNode> SmParser::DoFontSize() { DepthProtect aDepthGuard(m_nParseDepth); - if (aDepthGuard.TooDeep()) - throw std::range_error("parser depth limit"); - - assert(m_aCurToken.eType == TSIZE); - - FontSizeType Type; + if (aDepthGuard.TooDeep()) throw std::range_error("parser depth limit"); std::unique_ptr<SmFontNode> pFontNode(new SmFontNode(m_aCurToken)); - - NextToken(); + NextTokenFontSize(); + FontSizeType Type; switch (m_aCurToken.eType) { - case TNUMBER: Type = FontSizeType::ABSOLUT; break; + case THEX: Type = FontSizeType::ABSOLUT; break; case TPLUS: Type = FontSizeType::PLUS; break; case TMINUS: Type = FontSizeType::MINUS; break; case TMULTIPLY: Type = FontSizeType::MULTIPLY; break; @@ -1989,42 +2204,32 @@ std::unique_ptr<SmStructureNode> SmParser::DoFontSize() if (Type != FontSizeType::ABSOLUT) { - NextToken(); - if (m_aCurToken.eType != TNUMBER) - return DoError(SmParseError::SizeExpected); + NextTokenFontSize(); + if (m_aCurToken.eType != THEX) return DoError(SmParseError::SizeExpected); } // get number argument Fraction aValue( 1 ); if (lcl_IsNumber( m_aCurToken.aText )) { - double fTmp = m_aCurToken.aText.toDouble(); - if (fTmp != 0.0) + aValue = m_aCurToken.aText.toDouble(); + //!! Reduce values in order to avoid numerical errors + if (aValue.GetDenominator() > 1000) { - aValue = fTmp; - - //!! keep the numerator and denominator from being too large - //!! otherwise ongoing multiplications may result in overflows - //!! (for example in SmNode::SetFontSize the font size calculated - //!! may become 0 because of this!!! Happens e.g. for ftmp = 2.9 with Linux - //!! or ftmp = 1.11111111111111111... (11/9) on every platform.) - if (aValue.GetDenominator() > 1000) + tools::Long nNum = aValue.GetNumerator(); + tools::Long nDenom = aValue.GetDenominator(); + while ( nDenom > 1000 ) //remove big denominator { - tools::Long nNum = aValue.GetNumerator(); - tools::Long nDenom = aValue.GetDenominator(); - while (nDenom > 1000) - { - nNum /= 10; - nDenom /= 10; - } - aValue = Fraction( nNum, nDenom ); + nNum /= 10; + nDenom /= 10; } + aValue = Fraction( nNum, nDenom ); } } - - NextToken(); + else return DoError(SmParseError::SizeExpected); pFontNode->SetSizeParameter(aValue, Type); + NextToken(); return pFontNode; } @@ -2169,45 +2374,16 @@ std::unique_ptr<SmBracebodyNode> SmParser::DoBracebody(bool bIsLeftRight) std::unique_ptr<SmTextNode> SmParser::DoFunction() { DepthProtect aDepthGuard(m_nParseDepth); - if (aDepthGuard.TooDeep()) - throw std::range_error("parser depth limit"); - - switch (m_aCurToken.eType) + if (aDepthGuard.TooDeep()) throw std::range_error("parser depth limit"); + if( m_aCurToken.eType == TFUNC ) { - case TFUNC: - NextToken(); // skip "FUNC"-statement - m_aCurToken.eType = TFUNC; - [[fallthrough]]; - - case TSIN : - case TCOS : - case TTAN : - case TCOT : - case TASIN : - case TACOS : - case TATAN : - case TACOT : - case TSINH : - case TCOSH : - case TTANH : - case TCOTH : - case TASINH : - case TACOSH : - case TATANH : - case TACOTH : - case TLN : - case TLOG : - case TEXP : - { - auto pNode = std::make_unique<SmTextNode>(m_aCurToken, FNT_FUNCTION); - NextToken(); - return pNode; - } - - default: - assert(false); - return nullptr; + NextToken(); // skip "FUNC"-statement + m_aCurToken.eType = TFUNC; + m_aCurToken.nGroup = TG::Function; } + auto pNode = std::make_unique<SmTextNode>(m_aCurToken, FNT_FUNCTION); + NextToken(); + return pNode; } std::unique_ptr<SmTableNode> SmParser::DoBinom() @@ -2459,6 +2635,7 @@ void SmParser::AddError(SmParseError Type, SmNode *pNode) case SmParseError::SizeExpected: pRID = RID_ERR_SIZEEXPECTED; break; case SmParseError::DoubleAlign: pRID = RID_ERR_DOUBLEALIGN; break; case SmParseError::DoubleSubsupscript: pRID = RID_ERR_DOUBLESUBSUPSCRIPT; break; + case SmParseError::NumberExpected: pRID = RID_ERR_NUMBEREXPECTED; break; default: assert(false); return; diff --git a/starmath/source/visitors.cxx b/starmath/source/visitors.cxx index 3704abc18c32..f6e030b298d7 100644 --- a/starmath/source/visitors.cxx +++ b/starmath/source/visitors.cxx @@ -2077,8 +2077,8 @@ void SmNodeToTextVisitor::Visit( SmAttributNode* pNode ) void SmNodeToTextVisitor::Visit( SmFontNode* pNode ) { - sal_Int32 nc; - sal_Int16 nr, ng, nb; + sal_uInt32 nc; + sal_uInt8 nr, ng, nb; switch ( pNode->GetToken( ).eType ) { case TBOLD: @@ -2180,7 +2180,7 @@ void SmNodeToTextVisitor::Visit( SmFontNode* pNode ) break; case TRGB: Append( "color rgb " ); - nc = pNode->GetToken().aText.toInt32(); + nc = pNode->GetToken().aText.toUInt32(); nb = nc % 256; nc /= 256; ng = nc % 256; @@ -2193,6 +2193,30 @@ void SmNodeToTextVisitor::Visit( SmFontNode* pNode ) Append(OUString::number(nb)); Separate(); break; + case TRGBA: + Append( "color rgba " ); + nc = pNode->GetToken().aText.toUInt32(); + nb = nc % 256; + nc /= 256; + ng = nc % 256; + nc /= 256; + nr = nc % 256; + nc /= 256; + Append(OUString::number(nr)); + Separate(); + Append(OUString::number(ng)); + Separate(); + Append(OUString::number(nb)); + Separate(); + Append(OUString::number(nc)); + Separate(); + break; + case THEX: + Append( "color hex " ); + nc = pNode->GetToken().aText.toUInt32(); + Append(OUString::number(nc,16)); + Separate(); + break; case TSANS: Append( "font sans " ); break; @@ -2370,6 +2394,10 @@ void SmNodeToTextVisitor::Visit( SmTextNode* pNode ) Append("func "); Append( pNode->GetToken().aText ); break; + case THEX: + Append("hex "); + Append( pNode->GetToken().aText ); + break; default: Append( pNode->GetToken().aText ); } _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits