From 44c93e48e93425fef8e91f9d5147099863548b95 Mon Sep 17 00:00:00 2001 From: Ola Rinta-Koski Date: Tue, 8 Feb 2022 18:50:53 +0000 Subject: [PATCH] Markup parser fix: subscript/superscript/overbar handling --- common/font/font.cpp | 48 +++++++++++++------------- common/markup_parser.cpp | 15 ++++++-- include/markup_parser.h | 74 +++++++++++++++++++--------------------- 3 files changed, 73 insertions(+), 64 deletions(-) diff --git a/common/font/font.cpp b/common/font/font.cpp index 32be8d1692..92a380674a 100644 --- a/common/font/font.cpp +++ b/common/font/font.cpp @@ -196,35 +196,37 @@ VECTOR2I drawMarkup( BOX2I* aBoundingBox, std::vector>* a { VECTOR2I nextPosition = aPosition; - TEXT_STYLE_FLAGS textStyle = aTextStyle; + if( aNode ) { + TEXT_STYLE_FLAGS textStyle = aTextStyle; - if( !aNode->is_root() ) - { - if( aNode->isSubscript() ) - textStyle = TEXT_STYLE::SUBSCRIPT; - else if( aNode->isSuperscript() ) - textStyle = TEXT_STYLE::SUPERSCRIPT; - - if( aNode->isOverbar() ) - textStyle |= TEXT_STYLE::OVERBAR; - - if( aNode->has_content() ) + if( !aNode->is_root() ) { - std::string txt = aNode->string(); - BOX2I bbox; + if( aNode->isSubscript() ) + textStyle = TEXT_STYLE::SUBSCRIPT; + else if( aNode->isSuperscript() ) + textStyle = TEXT_STYLE::SUPERSCRIPT; - nextPosition = aFont->GetTextAsGlyphs( &bbox, aGlyphs, txt, aSize, aPosition, aAngle, - aMirror, aOrigin, textStyle ); + if( aNode->isOverbar() ) + textStyle |= TEXT_STYLE::OVERBAR; - if( aBoundingBox ) - aBoundingBox->Merge( bbox ); + if( aNode->has_content() ) + { + std::string txt = aNode->string(); + BOX2I bbox; + + nextPosition = aFont->GetTextAsGlyphs( &bbox, aGlyphs, txt, aSize, aPosition, aAngle, + aMirror, aOrigin, textStyle ); + + if( aBoundingBox ) + aBoundingBox->Merge( bbox ); + } } - } - for( const std::unique_ptr& child : aNode->children ) - { - nextPosition = drawMarkup( aBoundingBox, aGlyphs, child, nextPosition, aFont, aSize, - aAngle, aMirror, aOrigin, textStyle ); + for( const std::unique_ptr& child : aNode->children ) + { + nextPosition = drawMarkup( aBoundingBox, aGlyphs, child, nextPosition, aFont, aSize, + aAngle, aMirror, aOrigin, textStyle ); + } } return nextPosition; diff --git a/common/markup_parser.cpp b/common/markup_parser.cpp index a8805dfb2f..be2995c33e 100644 --- a/common/markup_parser.cpp +++ b/common/markup_parser.cpp @@ -27,9 +27,17 @@ using namespace MARKUP; std::unique_ptr MARKUP_PARSER::Parse() { - //string_input<> in( source, "from_input" ); - auto root = parse_tree::parse( in ); - return root; + try + { + auto root = parse_tree::parse( in ); + return root; + } + catch ( tao::pegtl::parse_error& parseError ) + { + // couldn't parse text item + // TODO message to user? + return nullptr; + } } @@ -39,6 +47,7 @@ std::string NODE::typeString() const if( is_type() ) os << "SUBSCRIPT"; else if( is_type() ) os << "SUPERSCRIPT"; + else if( is_type() ) os << "OVERBAR"; else if( is_type() ) os << "ANYSTRING"; else if( is_type() ) os << "ANYSTRINGWITHINBRACES"; else if( is_type() ) os << "VARNAMESPACENAME"; diff --git a/include/markup_parser.h b/include/markup_parser.h index 2408cde3a0..eef8402df5 100644 --- a/include/markup_parser.h +++ b/include/markup_parser.h @@ -47,66 +47,64 @@ struct NODE : parse_tree::basic_node bool isSuperscript() const { return is_type(); } }; -struct varPrefix : string<'$', '{'> {}; - -struct subPrefix : string<'_', '{'> {}; - -struct supPrefix : string<'^', '{'> {}; - -struct tildePrefix : string<'~', '{'> {}; - -struct closeBrace : string<'}'> {}; - struct varName : plus>> {}; struct varNamespaceName : plus {}; struct varNamespace : seq> {}; -struct variable : seq, varName, closeBrace> {}; +struct variable : seq< string< '$', '{' >, opt, varName, string< '}' > > {}; +template< typename ControlChar > +struct plain : seq< not_at< seq< ControlChar, string< '{' > > >, ControlChar > {}; + +struct plainControlChar : sor< plain< string<'$'> >, + plain< string<'_'> >, + plain< string<'^'> >, + plain< string<'~'> > > {}; /** * anyString = * a run of characters that do not start a command sequence, or if they do, they do not start * a complete command prefix (command char + open brace) */ -struct anyString : plus, - seq, string<'_'>>, - seq, string<'^'>>, - seq, string<'~'>>>> {}; +struct anyString : plus< sor< utf8::not_one< '~', '$', '_', '^' >, + plainControlChar > > {}; -struct prefixedSuperscript : seq {}; +struct anyStringWithinBraces : plus< sor< utf8::not_one< '~', '$', '_', '^', '}' >, + plainControlChar > > {}; -struct prefixedSubscript : seq {}; +template< typename ControlChar > +struct braces : seq< seq< ControlChar, string< '{' > >, + until< string< '}' >, sor< anyStringWithinBraces, + variable, + subscript, + superscript, + overbar > > > {}; -struct prefixedOverbar : seq {}; - -struct anyStringWithinBraces : plus>> {}; - -struct superscript : until> {}; - -struct subscript : until> {}; - -struct overbar : until> {}; +struct superscript : braces< string< '^' > > {}; +struct subscript : braces< string< '_' > > {}; +struct overbar : braces< string< '~' > > {}; /** * Finally, the full grammar */ -struct grammar : star> {}; +struct anything : sor< anyString, + variable, + subscript, + superscript, + overbar > {}; + +struct grammar : until< tao::pegtl::eof, anything > {}; template using selector = parse_tree::selector< Rule, - parse_tree::store_content::on, - parse_tree::discard_empty::on>; + parse_tree::store_content::on< varNamespaceName, + varName, + anyStringWithinBraces, + anyString >, + parse_tree::discard_empty::on< superscript, + subscript, + overbar > >; class MARKUP_PARSER {