LCOV - code coverage report
Current view: top level - src/engraving/infrastructure - htmlparser.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 94.0 % 84 79
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore-Studio-CLA-applies
       4              :  *
       5              :  * MuseScore Studio
       6              :  * Music Composition & Notation
       7              :  *
       8              :  * Copyright (C) 2021 MuseScore Limited and others
       9              :  *
      10              :  * This program is free software: you can redistribute it and/or modify
      11              :  * it under the terms of the GNU General Public License version 3 as
      12              :  * published by the Free Software Foundation.
      13              :  *
      14              :  * This program is distributed in the hope that it will be useful,
      15              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17              :  * GNU General Public License for more details.
      18              :  *
      19              :  * You should have received a copy of the GNU General Public License
      20              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      21              :  */
      22              : #include "htmlparser.h"
      23              : 
      24              : #include <string_view>
      25              : 
      26              : namespace mu::engraving {
      27           49 : muse::String HtmlParser::parse(const muse::String& in_html)
      28              : {
      29           49 :     if (in_html.isEmpty()) {
      30            0 :         return in_html;
      31              :     }
      32              : 
      33           49 :     std::string html = in_html.toStdString();
      34              : 
      35              :     //! NOTE Get body
      36           49 :     auto body_b = html.find("<body");
      37           49 :     auto body_e = html.find_last_of("</body>");
      38           49 :     if (body_b == std::string::npos || body_e == std::string::npos) {
      39            0 :         return in_html;
      40              :     }
      41           49 :     std::string body = html.substr(body_b, body_e - body_b);
      42              : 
      43           49 :     std::vector<std::string> blocks;
      44              : 
      45              :     //! NOTE Split blocks
      46           49 :     std::string::size_type p_b = 0;
      47           49 :     std::string::size_type p_e = 0;
      48              :     while (true) {
      49           98 :         p_b = body.find("<p", p_e);
      50           98 :         p_e = body.find("/p>", p_b);
      51           98 :         if (p_b == std::string::npos || p_e == std::string::npos) {
      52              :             break;
      53              :         }
      54              : 
      55           49 :         std::string block = body.substr(p_b, p_e - p_b);
      56           49 :         blocks.push_back(block);
      57           49 :     }
      58              : 
      59           49 :     if (blocks.empty()) {
      60            0 :         blocks.push_back(body);
      61              :     }
      62              : 
      63              :     //! NOTE Format blocks
      64           49 :     auto extractText = [](const std::string& block) {
      65           49 :         std::string text;
      66           49 :         bool isTag = false;
      67         7494 :         for (const char& c : block) {
      68         7445 :             if (c == '<') {
      69          145 :                 isTag = true;
      70         7300 :             } else if (c == '>') {
      71           96 :                 isTag = false;
      72         7204 :             } else if (!isTag) {
      73          279 :                 text += c;
      74              :             }
      75              :         }
      76           49 :         return text;
      77            0 :     };
      78              : 
      79           49 :     auto extractFont = [](const std::string& block) {
      80           49 :         auto fontsize_b = block.find("font-size");
      81           49 :         if (fontsize_b != std::string::npos) {
      82           16 :             std::string fontSize;
      83           16 :             bool started = false;
      84          206 :             for (auto i = fontsize_b; i < block.size(); ++i) {
      85          206 :                 const char& c = block.at(i);
      86          206 :                 if (strchr(".0123456789", c) != nullptr) {
      87           30 :                     started = true;
      88           30 :                     fontSize += c;
      89          176 :                 } else if (started) {
      90           16 :                     break;
      91              :                 }
      92              :             }
      93              : 
      94           48 :             return std::string("<font size=\"") + fontSize + std::string("\"/>");
      95           16 :         }
      96           33 :         return std::string();
      97              :     };
      98              : 
      99           49 :     auto formatRichText = [extractText, extractFont](const std::string& block) {
     100           49 :         std::string text = extractText(block);
     101           49 :         std::string font = extractFont(block);
     102           49 :         if (!font.empty()) {
     103           16 :             text = font + text;
     104              :         }
     105           49 :         return text;
     106           49 :     };
     107              : 
     108              :     //! NOTE Format rich text from blocks
     109           49 :     std::string text;
     110           98 :     for (const std::string& block : blocks) {
     111           49 :         if (!text.empty()) {
     112            0 :             text += "\n";
     113              :         }
     114              : 
     115           49 :         text += formatRichText(block);
     116              :     }
     117              : 
     118          686 :     auto replaceSym = [](std::string& str, int cc, std::string_view sym) {
     119          686 :         std::string code;
     120          686 :         code.resize(3);
     121          686 :         code[2] = static_cast<char>(cc);
     122          686 :         code[1] = static_cast<char>(cc >> 8);
     123          686 :         code[0] = static_cast<char>(cc >> 16);
     124              : 
     125          691 :         for (auto pos = str.find(code); pos != std::string::npos; pos = str.find(code, pos + sym.size())) {
     126            5 :             str.replace(pos, 3, sym);
     127              :         }
     128          686 :     };
     129              : 
     130              :     //! NOTE replace utf8 code /*utf16 code*/ on sym
     131           49 :     replaceSym(text, 0xee848e /*0xe10e*/, "<sym>accidentalNatural</sym>");        //natural
     132           49 :     replaceSym(text, 0xee848c /*0xe10c*/, "<sym>accidentalSharp</sym>");          // sharp
     133           49 :     replaceSym(text, 0xee848d /*0xe10d*/, "<sym>accidentalFlat</sym>");           // flat
     134           49 :     replaceSym(text, 0xee8484 /*0xe104*/, "<sym>metNoteHalfUp</sym>");            // note2_Sym
     135           49 :     replaceSym(text, 0xee8485 /*0xe105*/, "<sym>metNoteQuarterUp</sym>");         // note4_Sym
     136           49 :     replaceSym(text, 0xee8486 /*0xe106*/, "<sym>metNote8thUp</sym>");             // note8_Sym
     137           49 :     replaceSym(text, 0xee8487 /*0xe107*/, "<sym>metNote16thUp</sym>");            // note16_Sym
     138           49 :     replaceSym(text, 0xee8488 /*0xe108*/, "<sym>metNote32ndUp</sym>");            // note32_Sym
     139           49 :     replaceSym(text, 0xee8489 /*0xe109*/, "<sym>metNote64thUp</sym>");            // note64_Sym
     140           49 :     replaceSym(text, 0xee848a /*0xe10a*/, "<sym>metAugmentationDot</sym>");       // dot
     141           49 :     replaceSym(text, 0xee848b /*0xe10b*/, "<sym>metAugmentationDot</sym><sym>space</sym><sym>metAugmentationDot</sym>");          // dotdot
     142           49 :     replaceSym(text, 0xee85a7 /*0xe167*/, "<sym>segno</sym>");                    // segno
     143           49 :     replaceSym(text, 0xee85a8 /*0xe168*/, "<sym>coda</sym>");                     // coda
     144           49 :     replaceSym(text, 0xee85a9 /*0xe169*/, "<sym>codaSquare</sym>");               // varcoda
     145              : 
     146           49 :     return muse::String::fromStdString(text);
     147           49 : }
     148              : }
        

Generated by: LCOV version 2.0-1