diff --git a/importexport/musicxml/exportxml.cpp b/importexport/musicxml/exportxml.cpp index 0a2ea00baa52c..038b0d86e9570 100644 --- a/importexport/musicxml/exportxml.cpp +++ b/importexport/musicxml/exportxml.cpp @@ -3991,6 +3991,7 @@ static void beatUnit(XmlWriter& xml, const TDuration dur) static void wordsMetrome(XmlWriter& xml, Score* s, TextBase const* const text, const int offset) { //qDebug("wordsMetrome('%s')", qPrintable(text->xmlText())); + //qDebug("isTextInvalid %d isLayoutInvalid %d", text->isTextInvalid(), text->isLayoutInvalid()); const QList list = text->fragmentList(); QList wordsLeft; // words left of metronome bool hasParen; // parenthesis diff --git a/importexport/musicxml/musicxmlfonthandler.cpp b/importexport/musicxml/musicxmlfonthandler.cpp index e4c7998d40491..6ee44a06256fd 100644 --- a/importexport/musicxml/musicxmlfonthandler.cpp +++ b/importexport/musicxml/musicxmlfonthandler.cpp @@ -233,7 +233,7 @@ bool MScoreTextToMXML::split(const QList& in, const int pos, const void MScoreTextToMXML::writeTextFragments(const QList& fr, XmlWriter& xml) { - //qDebug("MScoreTextToMXML::writeTextFragments defFmt %s", qPrintable(charFormat2QString(oldFormat))); + //qDebug("MScoreTextToMXML::writeTextFragments"); //dumpText(fr); bool firstTime = true; // write additional attributes only the first time characters are written for (const TextFragment& f : fr) { diff --git a/libmscore/textbase.cpp b/libmscore/textbase.cpp index ba902c4eb70ca..931d9fd3def68 100644 --- a/libmscore/textbase.cpp +++ b/libmscore/textbase.cpp @@ -2382,6 +2382,44 @@ void TextBase::setXmlText(const QString& s) textInvalid = false; } +//--------------------------------------------------------- +// fragmentList +//--------------------------------------------------------- + +/* + Return the text as a single list of TextFragment + Used by the MusicXML formatted export to avoid parsing the xml text format + */ + +QList TextBase::fragmentList() const + { + QList res; + + const TextBase* text = this; + std::unique_ptr tmpText; + if (layoutInvalid) { + // Create temporary text object to avoid side effects + // of createLayout() call. + tmpText.reset(toTextBase(this->clone())); + tmpText->createLayout(); + text = tmpText.get(); + } + for (const TextBlock& block : text->_layout) { + for (const TextFragment& f : block.fragments()) { + /* TODO TBD + if (f.text.empty()) // skip empty fragments, not to + continue; // insert extra HTML formatting + */ + res.append(f); + if (block.eol()) { + // simply append a newline + res.last().text += "\n"; + } + } + } + return res; + } + //--------------------------------------------------------- // plainText // return plain text with symbols @@ -2650,34 +2688,6 @@ QString TextBase::subtypeName() const return score() ? score()->getTextStyleUserName(tid()) : textStyleUserName(tid()); } -//--------------------------------------------------------- -// fragmentList -//--------------------------------------------------------- - -/* - Return the text as a single list of TextFragment - Used by the MusicXML formatted export to avoid parsing the xml text format - */ - -QList TextBase::fragmentList() const - { - QList res; - for (const TextBlock& block : _layout) { - for (const TextFragment& f : block.fragments()) { - /* TODO TBD - if (f.text.empty()) // skip empty fragments, not to - continue; // insert extra HTML formatting - */ - res.append(f); - if (block.eol()) { - // simply append a newline - res.last().text += "\n"; - } - } - } - return res; - } - //--------------------------------------------------------- // validateText // check if s is a valid musescore xml text string diff --git a/mtest/musicxml/io/testInvalidLayout.mscx b/mtest/musicxml/io/testInvalidLayout.mscx new file mode 100644 index 0000000000000..f0015041219c4 --- /dev/null +++ b/mtest/musicxml/io/testInvalidLayout.mscx @@ -0,0 +1,227 @@ + + + 3.6.2 + 3224f34 + + + 0 + 480 + + 1 + 1 + 1 + 0 + + + + 2023-06-03 + + + + Linux + + + + + Issue #293441 test file by MuseScore 3.6.2 + + Orchestral + + Voices + +
+ flutes + oboes + clarinets + saxophones + bassoons + +
+
+ horns + trumpets + cornets + flugelhorns + trombones + tubas +
+
+ timpani +
+
+ keyboard-percussion + drums + unpitched-metal-percussion + unpitched-wooden-percussion + other-percussion +
+ keyboards + harps + organs + synths +
+ plucked-strings +
+ +
+ voices +
+
+ orchestral-strings +
+ +
+ + + + stdNormal + + + Voice + + Voice + Vo. + Voice + 38 + 84 + 41 + 79 + voice.vocals + + 100 + 100 + + + 100 + 33 + + + 100 + 50 + + + 100 + 67 + + + 100 + 100 + + + 120 + 67 + + + 150 + 100 + + + 150 + 50 + + + 120 + 50 + + + 120 + 100 + + + + + + Fluid + + + + + + 14.1434 + 0 + + + Issue #293441 test file by MuseScore 3.6.2 + + + + Verify a TextBase in a multimeasure rest is exported correctly +During MusicXML export, the TempoText contains an invalid layout + + + + + + + 0 + + 4 + 4 + + + 1.3333299999999999 + 1 + 1 + + metNoteQuarterUp = 80 + + + measure + 4/4 + + + + + + 3 + + + 0 + + -2 + + 4 + 4 + + + 1.3333299999999999 + 1 + 1 + + -2 + + metNoteQuarterUp = 80 + + + measure + 12/4 + + + + + + + + measure + 4/4 + + + + + + + + measure + 4/4 + + + + +
+
diff --git a/mtest/musicxml/io/testInvalidLayout_ref.xml b/mtest/musicxml/io/testInvalidLayout_ref.xml new file mode 100644 index 0000000000000..b96fdb5ab55d3 --- /dev/null +++ b/mtest/musicxml/io/testInvalidLayout_ref.xml @@ -0,0 +1,86 @@ + + + + + Issue #293441 test file by MuseScore 3.6.2 + + + + MuseScore 0.7.0 + 2007-09-10 + + + + + + + + + + Voice + Vo. + + Voice + + + + 1 + 53 + 78.7402 + 0 + + + + + + + 1 + + 0 + + + + G + 2 + + + 3 + + + + + + quarter + 80 + + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + light-heavy + + + + diff --git a/mtest/musicxml/io/tst_mxml_io.cpp b/mtest/musicxml/io/tst_mxml_io.cpp index 760a70d2172cc..d13bdf311e5c4 100644 --- a/mtest/musicxml/io/tst_mxml_io.cpp +++ b/mtest/musicxml/io/tst_mxml_io.cpp @@ -159,6 +159,7 @@ private slots: void inferredTransposition() { mxmlImportTestRef("testInferredTransposition"); } void instrumentChangeMIDIportExport() { mxmlMscxExportTestRef("testInstrumentChangeMIDIportExport"); } void instrumentSound() { mxmlIoTestRef("testInstrumentSound"); } + void invalidLayout() { mxmlMscxExportTestRef("testInvalidLayout"); } void invalidTimesig() { mxmlIoTestRef("testInvalidTimesig"); } void invisibleElements() { mxmlIoTest("testInvisibleElements"); } void keysig1() { mxmlIoTest("testKeysig1"); }