Skip to content

Commit

Permalink
Merge pull request musescore#18056 from Jojo-Schmitz/293441-direction…
Browse files Browse the repository at this point in the history
…-type-missing-child

Fix #293441: [MusicXML export] invalid XML export: direction-type is missing child element
  • Loading branch information
RomanPudashkin committed Jul 5, 2023
2 parents cac4112 + a658fca commit ab0b70d
Show file tree
Hide file tree
Showing 6 changed files with 355 additions and 30 deletions.
67 changes: 39 additions & 28 deletions src/engraving/libmscore/textbase.cpp
Expand Up @@ -2297,6 +2297,45 @@ void TextBase::resetFormatting()
cursor()->format()->setValign(VerticalAlignment::AlignNormal);
}

//---------------------------------------------------------
// fragmentList
//---------------------------------------------------------

/*
Return the text as a single list of TextFragment
Used by the MusicXML formatted export to avoid parsing the xml text format
*/

std::list<TextFragment> TextBase::fragmentList() const
{
std::list<TextFragment> res;

const TextBase* text = this;
std::unique_ptr<TextBase> 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->m_blocks) {
for (const TextFragment& f : block.fragments()) {
/* TODO TBD
if (f.text.empty()) // skip empty fragments, not to
continue; // insert extra HTML formatting
*/
res.push_back(f);
if (block.eol()) {
// simply append a newline
res.back().text += u"\n";
}
}
}
return res;
}

//---------------------------------------------------------
// plainText
// return plain text with symbols
Expand Down Expand Up @@ -2448,34 +2487,6 @@ TranslatableString TextBase::subtypeUserName() const
return score() ? score()->getTextStyleUserName(textStyleType()) : TConv::userName(textStyleType());
}

//---------------------------------------------------------
// fragmentList
//---------------------------------------------------------

/*
Return the text as a single list of TextFragment
Used by the MusicXML formatted export to avoid parsing the xml text format
*/

std::list<TextFragment> TextBase::fragmentList() const
{
std::list<TextFragment> res;
for (const TextBlock& block : m_blocks) {
for (const TextFragment& f : block.fragments()) {
/* TODO TBD
if (f.text.empty()) // skip empty fragments, not to
continue; // insert extra HTML formatting
*/
res.push_back(f);
if (block.eol()) {
// simply append a newline
res.back().text += u"\n";
}
}
}
return res;
}

//---------------------------------------------------------
// validateText
// check if s is a valid musescore xml text string
Expand Down
1 change: 0 additions & 1 deletion src/importexport/musicxml/internal/musicxml/exportxml.cpp
Expand Up @@ -4337,7 +4337,6 @@ static void beatUnit(XmlWriter& xml, const TDuration dur)

static void wordsMetronome(XmlWriter& xml, const MStyle& s, TextBase const* const text, const int offset)
{
//LOGD("wordsMetronome('%s')", qPrintable(text->xmlText()));
const std::list<TextFragment> list = text->fragmentList();
std::list<TextFragment> wordsLeft; // words left of metronome
bool hasParen; // parenthesis
Expand Down
Expand Up @@ -194,7 +194,6 @@ bool MScoreTextToMXML::split(const std::list<TextFragment>& in, const int pos, c

void MScoreTextToMXML::writeTextFragments(const std::list<TextFragment>& fr, XmlWriter& xml)
{
//LOGD("MScoreTextToMXML::writeTextFragments defFmt %s", qPrintable(charFormat2QString(oldFormat)));
//dumpText(fr);
bool firstTime = true; // write additional attributes only the first time characters are written
for (const TextFragment& f : fr) {
Expand Down
227 changes: 227 additions & 0 deletions src/importexport/musicxml/tests/data/testInvalidLayout.mscx
@@ -0,0 +1,227 @@
<?xml version="1.0" encoding="UTF-8"?>
<museScore version="3.02">
<programVersion>3.6.2</programVersion>
<programRevision>3224f34</programRevision>
<Score>
<LayerTag id="0" tag="default"></LayerTag>
<currentLayer>0</currentLayer>
<Division>480</Division>
<Style>
<pageWidth>8.27</pageWidth>
<pageHeight>11.69</pageHeight>
<enableVerticalSpread>1</enableVerticalSpread>
<createMultiMeasureRests>1</createMultiMeasureRests>
<Spatium>1.74978</Spatium>
</Style>
<showInvisible>1</showInvisible>
<showUnprintable>1</showUnprintable>
<showFrames>1</showFrames>
<showMargins>0</showMargins>
<metaTag name="arranger"></metaTag>
<metaTag name="composer"></metaTag>
<metaTag name="copyright"></metaTag>
<metaTag name="creationDate">2023-06-03</metaTag>
<metaTag name="lyricist"></metaTag>
<metaTag name="movementNumber"></metaTag>
<metaTag name="movementTitle"></metaTag>
<metaTag name="platform">Linux</metaTag>
<metaTag name="poet"></metaTag>
<metaTag name="source"></metaTag>
<metaTag name="translator"></metaTag>
<metaTag name="workNumber"></metaTag>
<metaTag name="workTitle">Issue #293441 test file by MuseScore 3.6.2</metaTag>
<Order id="orchestral" customized="1">
<name>Orchestral</name>
<instrument id="voice">
<family id="voices">Voices</family>
</instrument>
<section id="woodwind" brackets="true" showSystemMarkings="true" barLineSpan="true" thinBrackets="true">
<family>flutes</family>
<family>oboes</family>
<family>clarinets</family>
<family>saxophones</family>
<family>bassoons</family>
<unsorted group="woodwinds"/>
</section>
<section id="brass" brackets="true" showSystemMarkings="false" barLineSpan="true" thinBrackets="true">
<family>horns</family>
<family>trumpets</family>
<family>cornets</family>
<family>flugelhorns</family>
<family>trombones</family>
<family>tubas</family>
</section>
<section id="timpani" brackets="true" showSystemMarkings="false" barLineSpan="true" thinBrackets="true">
<family>timpani</family>
</section>
<section id="percussion" brackets="true" showSystemMarkings="false" barLineSpan="true" thinBrackets="true">
<family>keyboard-percussion</family>
<family>drums</family>
<family>unpitched-metal-percussion</family>
<family>unpitched-wooden-percussion</family>
<family>other-percussion</family>
</section>
<family>keyboards</family>
<family>harps</family>
<family>organs</family>
<family>synths</family>
<section id="plucked-strings" brackets="true" showSystemMarkings="false" barLineSpan="true" thinBrackets="true">
<family>plucked-strings</family>
</section>
<soloists/>
<section id="voices" brackets="true" showSystemMarkings="false" barLineSpan="false" thinBrackets="true">
<family>voices</family>
</section>
<section id="strings" brackets="true" showSystemMarkings="true" barLineSpan="true" thinBrackets="true">
<family>orchestral-strings</family>
</section>
<unsorted/>
</Order>
<Part>
<Staff id="1">
<StaffType group="pitched">
<name>stdNormal</name>
</StaffType>
</Staff>
<trackName>Voice</trackName>
<Instrument id="voice">
<longName>Voice</longName>
<shortName>Vo.</shortName>
<trackName>Voice</trackName>
<minPitchP>38</minPitchP>
<maxPitchP>84</maxPitchP>
<minPitchA>41</minPitchA>
<maxPitchA>79</maxPitchA>
<instrumentId>voice.vocals</instrumentId>
<Articulation>
<velocity>100</velocity>
<gateTime>100</gateTime>
</Articulation>
<Articulation name="staccatissimo">
<velocity>100</velocity>
<gateTime>33</gateTime>
</Articulation>
<Articulation name="staccato">
<velocity>100</velocity>
<gateTime>50</gateTime>
</Articulation>
<Articulation name="portato">
<velocity>100</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="tenuto">
<velocity>100</velocity>
<gateTime>100</gateTime>
</Articulation>
<Articulation name="marcato">
<velocity>120</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="sforzato">
<velocity>150</velocity>
<gateTime>100</gateTime>
</Articulation>
<Articulation name="sforzatoStaccato">
<velocity>150</velocity>
<gateTime>50</gateTime>
</Articulation>
<Articulation name="marcatoStaccato">
<velocity>120</velocity>
<gateTime>50</gateTime>
</Articulation>
<Articulation name="marcatoTenuto">
<velocity>120</velocity>
<gateTime>100</gateTime>
</Articulation>
<Channel>
<controller ctrl="0" value="0"/>
<controller ctrl="32" value="17"/>
<program value="52"/>
<synti>Fluid</synti>
</Channel>
</Instrument>
</Part>
<Staff id="1">
<VBox>
<height>14.1434</height>
<boxAutoSize>0</boxAutoSize>
<Text>
<style>Title</style>
<text>Issue #293441 test file by MuseScore 3.6.2</text>
</Text>
<Text>
<style>Subtitle</style>
<text>Verify a TextBase in a multimeasure rest is exported correctly
During MusicXML export, the TempoText contains an invalid layout</text>
</Text>
</VBox>
<!-- Measure 1 -->
<Measure>
<voice>
<TimeSig>
<lid>0</lid>
<linkedMain/>
<sigN>4</sigN>
<sigD>4</sigD>
</TimeSig>
<Tempo>
<tempo>1.3333299999999999</tempo>
<followText>1</followText>
<lid>1</lid>
<linkedMain/>
<text><sym>metNoteQuarterUp</sym> = 80</text>
</Tempo>
<Rest>
<durationType>measure</durationType>
<duration>4/4</duration>
</Rest>
</voice>
</Measure>
<!-- Measure 1 -->
<Measure len="12/4">
<multiMeasureRest>3</multiMeasureRest>
<voice>
<TimeSig>
<lid>0</lid>
<linked>
<indexDiff>-2</indexDiff>
</linked>
<sigN>4</sigN>
<sigD>4</sigD>
</TimeSig>
<Tempo>
<tempo>1.3333299999999999</tempo>
<followText>1</followText>
<lid>1</lid>
<linked>
<indexDiff>-2</indexDiff>
</linked>
<text><sym>metNoteQuarterUp</sym> = 80</text>
</Tempo>
<Rest>
<durationType>measure</durationType>
<duration>12/4</duration>
</Rest>
</voice>
</Measure>
<!-- Measure 2 -->
<Measure>
<voice>
<Rest>
<durationType>measure</durationType>
<duration>4/4</duration>
</Rest>
</voice>
</Measure>
<!-- Measure 3 -->
<Measure>
<voice>
<Rest>
<durationType>measure</durationType>
<duration>4/4</duration>
</Rest>
</voice>
</Measure>
</Staff>
</Score>
</museScore>

0 comments on commit ab0b70d

Please sign in to comment.