LCOV - code coverage report
Current view: top level - src/engraving/rw/read500 - tread.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 52.8 % 3430 1810
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) 2026 MuseScore Limited
       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              : 
      23              : #include "tread.h"
      24              : 
      25              : #include "iengravingconfiguration.h" // IWYU pragma: keep
      26              : 
      27              : #include "../../types/typesconv.h"
      28              : #include "../../types/symnames.h"
      29              : #include "../../infrastructure/rtti.h"
      30              : #include "../../infrastructure/htmlparser.h"
      31              : 
      32              : #include "../../compat/midi/event.h"
      33              : 
      34              : #include "../../dom/accidental.h"
      35              : #include "../../dom/actionicon.h"
      36              : #include "../../dom/ambitus.h"
      37              : #include "../../dom/arpeggio.h"
      38              : #include "../../dom/articulation.h"
      39              : #include "../../dom/bagpembell.h"
      40              : #include "../../dom/barline.h"
      41              : #include "../../dom/beam.h"
      42              : #include "../../dom/bend.h"
      43              : #include "../../dom/box.h"
      44              : #include "../../dom/bracket.h"
      45              : #include "../../dom/breath.h"
      46              : #include "../../dom/capo.h"
      47              : #include "../../dom/chord.h"
      48              : #include "../../dom/chordbracket.h"
      49              : #include "../../dom/chordline.h"
      50              : #include "../../dom/chordlist.h"
      51              : #include "../../dom/clef.h"
      52              : #include "../../dom/drumset.h"
      53              : #include "../../dom/dynamic.h"
      54              : #include "../../dom/excerpt.h"
      55              : #include "../../dom/expression.h"
      56              : #include "../../dom/factory.h"
      57              : #include "../../dom/fermata.h"
      58              : #include "../../dom/figuredbass.h"
      59              : #include "../../dom/fingering.h"
      60              : #include "../../dom/fret.h"
      61              : #include "../../dom/glissando.h"
      62              : #include "../../dom/gradualtempochange.h"
      63              : #include "../../dom/groups.h"
      64              : #include "../../dom/guitarbend.h"
      65              : #include "../../dom/hairpin.h"
      66              : #include "../../dom/hammeronpulloff.h"
      67              : #include "../../dom/harmonicmark.h"
      68              : #include "../../dom/harmony.h"
      69              : #include "../../dom/harppedaldiagram.h"
      70              : #include "../../dom/hook.h"
      71              : #include "../../dom/image.h"
      72              : #include "../../dom/instrchange.h"
      73              : #include "../../dom/instrument.h"
      74              : #include "../../dom/jump.h"
      75              : #include "../../dom/keysig.h"
      76              : #include "../../dom/laissezvib.h"
      77              : #include "../../dom/layoutbreak.h"
      78              : #include "../../dom/ledgerline.h"
      79              : #include "../../dom/letring.h"
      80              : #include "../../dom/line.h"
      81              : #include "../../dom/linkedobjects.h"
      82              : #include "../../dom/lyrics.h"
      83              : #include "../../dom/marker.h"
      84              : #include "../../dom/masterscore.h"
      85              : #include "../../dom/measure.h"
      86              : #include "../../dom/measurenumber.h"
      87              : #include "../../dom/measurerepeat.h"
      88              : #include "../../dom/mmrest.h"
      89              : #include "../../dom/mmrestrange.h"
      90              : #include "../../dom/mscore.h"
      91              : #include "../../dom/note.h"
      92              : #include "../../dom/notedot.h"
      93              : #include "../../dom/noteline.h"
      94              : #include "../../dom/ornament.h"
      95              : #include "../../dom/ottava.h"
      96              : #include "../../dom/page.h"
      97              : #include "../../dom/palmmute.h"
      98              : #include "../../dom/parenthesis.h"
      99              : #include "../../dom/part.h"
     100              : #include "../../dom/partialtie.h"
     101              : #include "../../dom/pedal.h"
     102              : #include "../../dom/playcounttext.h"
     103              : #include "../../dom/playtechannotation.h"
     104              : #include "../../dom/rasgueado.h"
     105              : #include "../../dom/rehearsalmark.h"
     106              : #include "../../dom/rest.h"
     107              : #include "../../dom/score.h"
     108              : #include "../../dom/segment.h"
     109              : #include "../../dom/sharedpart.h"
     110              : #include "../../dom/slur.h"
     111              : #include "../../dom/slurtie.h"
     112              : #include "../../dom/soundflag.h"
     113              : #include "../../dom/spacer.h"
     114              : #include "../../dom/spanner.h"
     115              : #include "../../dom/staff.h"
     116              : #include "../../dom/staffstate.h"
     117              : #include "../../dom/stafftext.h"
     118              : #include "../../dom/stafftextbase.h"
     119              : #include "../../dom/stafftype.h"
     120              : #include "../../dom/stafftypechange.h"
     121              : #include "../../dom/stavesharinglabel.h"
     122              : #include "../../dom/stem.h"
     123              : #include "../../dom/stemslash.h"
     124              : #include "../../dom/sticking.h"
     125              : #include "../../dom/stringtunings.h"
     126              : #include "../../dom/system.h"
     127              : #include "../../dom/systemdivider.h"
     128              : #include "../../dom/systemtext.h"
     129              : #include "../../dom/tapping.h"
     130              : #include "../../dom/tempotext.h"
     131              : #include "../../dom/text.h"
     132              : #include "../../dom/textline.h"
     133              : #include "../../dom/textlinebase.h"
     134              : #include "../../dom/tie.h"
     135              : #include "../../dom/timesig.h"
     136              : #include "../../dom/tremolobar.h"
     137              : #include "../../dom/tremolosinglechord.h"
     138              : #include "../../dom/tremolotwochord.h"
     139              : #include "../../dom/trill.h"
     140              : #include "../../dom/tuplet.h"
     141              : #include "../../dom/vibrato.h"
     142              : #include "../../dom/volta.h"
     143              : #include "../../dom/whammybar.h"
     144              : 
     145              : #include "../../editing/editstaffbrackets.h"
     146              : 
     147              : #include "../xmlreader.h"
     148              : #include "../read206/read206.h"
     149              : #include "../compat/compatutils.h"
     150              : #include "../compat/tremolocompat.h"
     151              : #include "readcontext.h"
     152              : 
     153              : #include "log.h"
     154              : 
     155              : using namespace muse::draw;
     156              : using namespace mu::engraving;
     157              : using namespace mu::engraving::read500;
     158              : 
     159         1425 : void TRead::readItem(EngravingItem* item, XmlReader& xml, ReadContext& ctx)
     160              : {
     161         1425 :     switch (item->type()) {
     162            0 :     case ElementType::ACCIDENTAL: read(item_cast<Accidental*>(item), xml, ctx);
     163            0 :         break;
     164            0 :     case ElementType::ACTION_ICON: read(item_cast<ActionIcon*>(item), xml, ctx);
     165            0 :         break;
     166            0 :     case ElementType::AMBITUS: read(item_cast<Ambitus*>(item), xml, ctx);
     167            0 :         break;
     168            0 :     case ElementType::ARPEGGIO: read(item_cast<Arpeggio*>(item), xml, ctx);
     169            0 :         break;
     170            0 :     case ElementType::CHORD_BRACKET: read(item_cast<ChordBracket*>(item), xml, ctx);
     171            0 :         break;
     172           22 :     case ElementType::ARTICULATION: read(item_cast<Articulation*>(item), xml, ctx);
     173           22 :         break;
     174            0 :     case ElementType::TAPPING: read(item_cast<Tapping*>(item), xml, ctx);
     175            0 :         break;
     176            0 :     case ElementType::BAGPIPE_EMBELLISHMENT: read(item_cast<BagpipeEmbellishment*>(item), xml, ctx);
     177            0 :         break;
     178            0 :     case ElementType::BAR_LINE: read(item_cast<BarLine*>(item), xml, ctx);
     179            0 :         break;
     180            0 :     case ElementType::BEAM: read(item_cast<Beam*>(item), xml, ctx);
     181            0 :         break;
     182            0 :     case ElementType::BEND: read(item_cast<Bend*>(item), xml, ctx);
     183            0 :         break;
     184           13 :     case ElementType::HBOX: read(item_cast<HBox*>(item), xml, ctx);
     185           13 :         break;
     186          156 :     case ElementType::VBOX: read(item_cast<VBox*>(item), xml, ctx);
     187          156 :         break;
     188            0 :     case ElementType::FBOX: read(item_cast<FBox*>(item), xml, ctx);
     189            0 :         break;
     190            1 :     case ElementType::TBOX: read(item_cast<TBox*>(item), xml, ctx);
     191            1 :         break;
     192            0 :     case ElementType::BRACKET: read(item_cast<Bracket*>(item), xml, ctx);
     193            0 :         break;
     194            0 :     case ElementType::BREATH: read(item_cast<Breath*>(item), xml, ctx);
     195            0 :         break;
     196          326 :     case ElementType::CHORD: read(item_cast<Chord*>(item), xml, ctx);
     197          326 :         break;
     198            1 :     case ElementType::CHORDLINE: read(item_cast<ChordLine*>(item), xml, ctx);
     199            1 :         break;
     200            0 :     case ElementType::CLEF: read(item_cast<Clef*>(item), xml, ctx);
     201            0 :         break;
     202            0 :     case ElementType::CAPO: read(item_cast<Capo*>(item), xml, ctx);
     203            0 :         break;
     204           17 :     case ElementType::DYNAMIC: read(item_cast<Dynamic*>(item), xml, ctx);
     205           17 :         break;
     206            0 :     case ElementType::EXPRESSION: read(item_cast<Expression*>(item), xml, ctx);
     207            0 :         break;
     208            1 :     case ElementType::FERMATA: read(item_cast<Fermata*>(item), xml, ctx);
     209            1 :         break;
     210            0 :     case ElementType::FIGURED_BASS: read(item_cast<FiguredBass*>(item), xml, ctx);
     211            0 :         break;
     212            0 :     case ElementType::FINGERING: read(item_cast<Fingering*>(item), xml, ctx);
     213            0 :         break;
     214            0 :     case ElementType::FRET_DIAGRAM: read(item_cast<FretDiagram*>(item), xml, ctx);
     215            0 :         break;
     216            4 :     case ElementType::GLISSANDO: read(item_cast<Glissando*>(item), xml, ctx);
     217            4 :         break;
     218           41 :     case ElementType::GRADUAL_TEMPO_CHANGE: read(item_cast<GradualTempoChange*>(item), xml, ctx);
     219           41 :         break;
     220            4 :     case ElementType::GUITAR_BEND: read(item_cast<GuitarBend*>(item), xml, ctx);
     221            4 :         break;
     222           68 :     case ElementType::HAIRPIN: read(item_cast<Hairpin*>(item), xml, ctx);
     223           68 :         break;
     224            0 :     case ElementType::HAMMER_ON_PULL_OFF: read(item_cast<HammerOnPullOff*>(item), xml, ctx);
     225            0 :         break;
     226            0 :     case ElementType::HARMONY: read(item_cast<Harmony*>(item), xml, ctx);
     227            0 :         break;
     228           30 :     case ElementType::HARMONIC_MARK: read(item_cast<HarmonicMark*>(item), xml, ctx);
     229           30 :         break;
     230            7 :     case ElementType::HARP_DIAGRAM: read(item_cast<HarpPedalDiagram*>(item), xml, ctx);
     231            7 :         break;
     232            0 :     case ElementType::HOOK: read(item_cast<Hook*>(item), xml, ctx);
     233            0 :         break;
     234            0 :     case ElementType::IMAGE: read(item_cast<Image*>(item), xml, ctx);
     235            0 :         break;
     236            6 :     case ElementType::INSTRUMENT_CHANGE: read(item_cast<InstrumentChange*>(item), xml, ctx);
     237            6 :         break;
     238            2 :     case ElementType::JUMP: read(item_cast<Jump*>(item), xml, ctx);
     239            2 :         break;
     240            0 :     case ElementType::KEYSIG: read(item_cast<KeySig*>(item), xml, ctx);
     241            0 :         break;
     242            0 :     case ElementType::LAISSEZ_VIB: read(item_cast<LaissezVib*>(item), xml, ctx);
     243            0 :         break;
     244            0 :     case ElementType::LAYOUT_BREAK: read(item_cast<LayoutBreak*>(item), xml, ctx);
     245            0 :         break;
     246            0 :     case ElementType::LEDGER_LINE: read(item_cast<LedgerLine*>(item), xml, ctx);
     247            0 :         break;
     248           30 :     case ElementType::LET_RING: read(item_cast<LetRing*>(item), xml, ctx);
     249           30 :         break;
     250            2 :     case ElementType::LYRICS: read(item_cast<Lyrics*>(item), xml, ctx);
     251            2 :         break;
     252            1 :     case ElementType::LYRICSLINE: read(item_cast<LyricsLine*>(item), xml, ctx);
     253            1 :         break;
     254            4 :     case ElementType::MARKER: read(item_cast<Marker*>(item), xml, ctx);
     255            4 :         break;
     256            0 :     case ElementType::MEASURE_NUMBER: read(item_cast<MeasureNumber*>(item), xml, ctx);
     257            0 :         break;
     258            0 :     case ElementType::MEASURE_REPEAT: read(item_cast<MeasureRepeat*>(item), xml, ctx);
     259            0 :         break;
     260            0 :     case ElementType::MMREST: read(item_cast<MMRest*>(item), xml, ctx);
     261            0 :         break;
     262            0 :     case ElementType::MMREST_RANGE: read(item_cast<MMRestRange*>(item), xml, ctx);
     263            0 :         break;
     264          205 :     case ElementType::NOTE: read(item_cast<Note*>(item), xml, ctx);
     265          205 :         break;
     266            0 :     case ElementType::NOTEDOT: read(item_cast<NoteDot*>(item), xml, ctx);
     267            0 :         break;
     268            0 :     case ElementType::NOTEHEAD: read(item_cast<NoteHead*>(item), xml, ctx);
     269            0 :         break;
     270            1 :     case ElementType::NOTELINE: read(item_cast<NoteLine*>(item), xml, ctx);
     271            1 :         break;
     272            0 :     case ElementType::PAGE: read(item_cast<Page*>(item), xml, ctx);
     273            0 :         break;
     274           38 :     case ElementType::PALM_MUTE: read(item_cast<PalmMute*>(item), xml, ctx);
     275           38 :         break;
     276            5 :     case ElementType::PARTIAL_LYRICSLINE: read(item_cast<PartialLyricsLine*>(item), xml, ctx);
     277            5 :         break;
     278            0 :     case ElementType::PARTIAL_TIE: read(item_cast<PartialTie*>(item), xml, ctx);
     279            0 :         break;
     280           41 :     case ElementType::PEDAL: read(item_cast<Pedal*>(item), xml, ctx);
     281           41 :         break;
     282            0 :     case ElementType::PLAY_COUNT_TEXT: read(item_cast<PlayCountText*>(item), xml, ctx);
     283            0 :         break;
     284            0 :     case ElementType::PLAYTECH_ANNOTATION: read(item_cast<PlayTechAnnotation*>(item), xml, ctx);
     285            0 :         break;
     286           30 :     case ElementType::RASGUEADO: read(item_cast<Rasgueado*>(item), xml, ctx);
     287           30 :         break;
     288            0 :     case ElementType::REHEARSAL_MARK: read(item_cast<RehearsalMark*>(item), xml, ctx);
     289            0 :         break;
     290          137 :     case ElementType::REST: read(item_cast<Rest*>(item), xml, ctx);
     291          137 :         break;
     292            3 :     case ElementType::ORNAMENT: read(item_cast<Ornament*>(item), xml, ctx);
     293            3 :         break;
     294           41 :     case ElementType::OTTAVA: read(item_cast<Ottava*>(item), xml, ctx);
     295           41 :         break;
     296            0 :     case ElementType::SEGMENT: read(item_cast<Segment*>(item), xml, ctx);
     297            0 :         break;
     298           30 :     case ElementType::SLUR: read(item_cast<Slur*>(item), xml, ctx);
     299           30 :         break;
     300            0 :     case ElementType::SPACER: read(item_cast<Spacer*>(item), xml, ctx);
     301            0 :         break;
     302            0 :     case ElementType::STAFF_STATE: read(item_cast<StaffState*>(item), xml, ctx);
     303            0 :         break;
     304           15 :     case ElementType::STAFF_TEXT: read(item_cast<StaffText*>(item), xml, ctx);
     305           15 :         break;
     306            0 :     case ElementType::STAVE_SHARING_LABEL: read(item_cast<StaveSharingLabel*>(item), xml, ctx);
     307            0 :         break;
     308            0 :     case ElementType::STAFFTYPE_CHANGE: read(item_cast<StaffTypeChange*>(item), xml, ctx);
     309            0 :         break;
     310            0 :     case ElementType::STEM: read(item_cast<Stem*>(item), xml, ctx);
     311            0 :         break;
     312            0 :     case ElementType::STEM_SLASH: read(item_cast<StemSlash*>(item), xml, ctx);
     313            0 :         break;
     314           15 :     case ElementType::STICKING: read(item_cast<Sticking*>(item), xml, ctx);
     315           15 :         break;
     316            0 :     case ElementType::STRING_TUNINGS: read(item_cast<StringTunings*>(item), xml, ctx);
     317            0 :         break;
     318            0 :     case ElementType::SYMBOL: read(item_cast<Symbol*>(item), xml, ctx);
     319            0 :         break;
     320            0 :     case ElementType::SOUND_FLAG: read(item_cast<SoundFlag*>(item), xml, ctx);
     321            0 :         break;
     322            0 :     case ElementType::FSYMBOL: read(item_cast<FSymbol*>(item), xml, ctx);
     323            0 :         break;
     324            0 :     case ElementType::SYSTEM: read(item_cast<System*>(item), xml, ctx);
     325            0 :         break;
     326            0 :     case ElementType::SYSTEM_DIVIDER: read(item_cast<SystemDivider*>(item), xml, ctx);
     327            0 :         break;
     328            1 :     case ElementType::SYSTEM_TEXT: read(item_cast<SystemText*>(item), xml, ctx);
     329            1 :         break;
     330            0 :     case ElementType::TEMPO_TEXT: read(item_cast<TempoText*>(item), xml, ctx);
     331            0 :         break;
     332            0 :     case ElementType::TEXT: read(item_cast<Text*>(item), xml, ctx);
     333            0 :         break;
     334           37 :     case ElementType::TEXTLINE: read(item_cast<TextLine*>(item), xml, ctx);
     335           37 :         break;
     336           32 :     case ElementType::TIE: read(item_cast<Tie*>(item), xml, ctx);
     337           32 :         break;
     338            0 :     case ElementType::TIMESIG: read(item_cast<TimeSig*>(item), xml, ctx);
     339            0 :         break;
     340           17 :     case ElementType::TREMOLO_SINGLECHORD: read(item_cast<TremoloSingleChord*>(item), xml, ctx);
     341           17 :         break;
     342            0 :     case ElementType::TREMOLO_TWOCHORD: read(item_cast<TremoloTwoChord*>(item), xml, ctx);
     343            0 :         break;
     344            0 :     case ElementType::TREMOLOBAR: read(item_cast<TremoloBar*>(item), xml, ctx);
     345            0 :         break;
     346            2 :     case ElementType::TRILL: read(item_cast<Trill*>(item), xml, ctx);
     347            2 :         break;
     348            0 :     case ElementType::TUPLET: read(item_cast<Tuplet*>(item), xml, ctx);
     349            0 :         break;
     350            1 :     case ElementType::VIBRATO: read(item_cast<Vibrato*>(item), xml, ctx);
     351            1 :         break;
     352            7 :     case ElementType::VOLTA: read(item_cast<Volta*>(item), xml, ctx);
     353            7 :         break;
     354           31 :     case ElementType::WHAMMY_BAR: read(item_cast<WhammyBar*>(item), xml, ctx);
     355           31 :         break;
     356            0 :     default:
     357            0 :         UNREACHABLE;
     358              :         LOGE() << "Not implemented read for type: " << item->typeName();
     359              :         break;
     360              :     }
     361         1425 : }
     362              : 
     363         1657 : PropertyValue TRead::readPropertyValue(Pid id, XmlReader& e, ReadContext& ctx)
     364              : {
     365         1657 :     switch (propertyType(id)) {
     366          158 :     case P_TYPE::BOOL:
     367          158 :         return PropertyValue(bool(e.readInt()));
     368           71 :     case P_TYPE::INT:
     369              :     case P_TYPE::SIZE_T:
     370           71 :         return PropertyValue(e.readInt());
     371          123 :     case P_TYPE::REAL:
     372          123 :         return PropertyValue(e.readDouble());
     373          173 :     case P_TYPE::SPATIUM: return PropertyValue(Spatium(e.readDouble()));
     374            0 :     case P_TYPE::ABSOLUTE: return PropertyValue(Spatium(e.readDouble())); //! NOTE type mm, but stored in xml as spatium
     375            0 :     case P_TYPE::TEMPO:
     376            0 :         return PropertyValue(e.readDouble());
     377            0 :     case P_TYPE::FRACTION:
     378            0 :         return PropertyValue::fromValue(e.readFraction());
     379              : 
     380            0 :     case P_TYPE::SYMID:
     381            0 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), SymId::noSym));
     382            1 :     case P_TYPE::COLOR:
     383            1 :         return PropertyValue::fromValue(e.readColor());
     384            0 :     case P_TYPE::ORNAMENT_STYLE:
     385            0 :         return PropertyValue::fromValue(TConv::fromXml(e.readAsciiText(), OrnamentStyle::DEFAULT));
     386            1 :     case P_TYPE::ORNAMENT_INTERVAL:
     387            1 :         return PropertyValue(TConv::fromXml(e.readText(), DEFAULT_ORNAMENT_INTERVAL));
     388            0 :     case P_TYPE::ORNAMENT_SHOW_ACCIDENTAL:
     389            0 :         return OrnamentShowAccidental(e.readInt());
     390          173 :     case P_TYPE::POINT:
     391          173 :         return PropertyValue::fromValue(e.readPoint());
     392            0 :     case P_TYPE::SCALE:
     393            0 :         return PropertyValue::fromValue(e.readScale());
     394            0 :     case P_TYPE::SIZE:
     395            0 :         return PropertyValue::fromValue(e.readSize());
     396           53 :     case P_TYPE::STRING:
     397           53 :         return PropertyValue(e.readText());
     398              : 
     399           30 :     case P_TYPE::ALIGN:
     400           30 :         return PropertyValue(TConv::fromXml(e.readText(), Align()));
     401           30 :     case P_TYPE::ALIGN_H:
     402           30 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), AlignH::HCENTER));
     403           27 :     case P_TYPE::PLACEMENT_V:
     404           27 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), PlacementV::ABOVE));
     405            0 :     case P_TYPE::PLACEMENT_H:
     406            0 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), PlacementH::LEFT));
     407           82 :     case P_TYPE::TEXT_PLACE:
     408           82 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), TextPlace::AUTO));
     409          227 :     case P_TYPE::DIRECTION_V:
     410          227 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), DirectionV::AUTO));
     411            7 :     case P_TYPE::DIRECTION_H:
     412            7 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), DirectionH::AUTO));
     413            0 :     case P_TYPE::ORIENTATION:
     414            0 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), Orientation::VERTICAL));
     415              : 
     416          103 :     case P_TYPE::LAYOUTBREAK_TYPE:
     417          103 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), LayoutBreakType::NOBREAK));
     418            0 :     case P_TYPE::VELO_TYPE:
     419            0 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), VeloType::OFFSET_VAL));
     420            0 :     case P_TYPE::GLISS_STYLE:
     421            0 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), GlissandoStyle::CHROMATIC));
     422            0 :     case P_TYPE::GLISS_TYPE:
     423            0 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), GlissandoType::STRAIGHT));
     424            0 :     case P_TYPE::BARLINE_TYPE:
     425            0 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), BarLineType::NORMAL));
     426              : 
     427          106 :     case P_TYPE::NOTEHEAD_TYPE:
     428          106 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), NoteHeadType::HEAD_AUTO));
     429            3 :     case P_TYPE::NOTEHEAD_SCHEME:
     430            3 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), NoteHeadScheme::HEAD_AUTO));
     431          181 :     case P_TYPE::NOTEHEAD_GROUP:
     432          181 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), NoteHeadGroup::HEAD_NORMAL));
     433              : 
     434            0 :     case P_TYPE::CLEF_TYPE:
     435            0 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), ClefType::G));
     436            0 :     case P_TYPE::CLEF_TO_BARLINE_POS:
     437            0 :         return ClefToBarlinePosition(e.readInt());
     438              : 
     439            0 :     case P_TYPE::DYNAMIC_TYPE:
     440            0 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), DynamicType::OTHER));
     441              : 
     442           10 :     case P_TYPE::LINE_TYPE:
     443           10 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), LineType::SOLID));
     444           51 :     case P_TYPE::HOOK_TYPE:
     445           51 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), HookType::NONE));
     446              : 
     447            0 :     case P_TYPE::KEY_MODE:
     448            0 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), KeyMode::NONE));
     449              : 
     450           13 :     case P_TYPE::TEXT_STYLE:
     451           13 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), TextStyleType::DEFAULT));
     452            0 :     case P_TYPE::SLUR_STYLE_TYPE:
     453            0 :         return SlurStyleType(e.readInt());
     454              : 
     455            0 :     case P_TYPE::CHANGE_METHOD:
     456            0 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), ChangeMethod::NORMAL));
     457              : 
     458            0 :     case P_TYPE::BEAM_MODE:
     459            0 :         return PropertyValue(int(0));
     460            0 :     case P_TYPE::GROUPS: {
     461            0 :         Groups g;
     462            0 :         TRead::read(&g, e, ctx);
     463            0 :         return PropertyValue::fromValue(g.nodes());
     464            0 :     }
     465            0 :     case P_TYPE::DURATION_TYPE_WITH_DOTS:
     466              :     case P_TYPE::INT_VEC:
     467            0 :         return PropertyValue(TConv::fromXml(String(e.readText()), std::vector<int>()));
     468              : 
     469            0 :     case P_TYPE::PLAYTECH_TYPE:
     470            0 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), PlayingTechniqueType::Natural));
     471            2 :     case P_TYPE::TEMPOCHANGE_TYPE:
     472            2 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), GradualTempoChangeType::Undefined));
     473            0 :     case P_TYPE::TIE_PLACEMENT:
     474            0 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), TiePlacement::AUTO));
     475            2 :     case P_TYPE::VOICE_ASSIGNMENT:
     476            2 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), VoiceAssignment::ALL_VOICE_IN_INSTRUMENT));
     477            2 :     case P_TYPE::AUTO_ON_OFF:
     478            2 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), AutoOnOff::AUTO));
     479           21 :     case P_TYPE::PARTIAL_SPANNER_DIRECTION:
     480           21 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), PartialSpannerDirection::OUTGOING));
     481            3 :     case P_TYPE::PARENTHESES_MODE:
     482            3 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), ParenthesesMode::NONE));
     483            0 :     case P_TYPE::AUTO_CUSTOM_HIDE:
     484            0 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), AutoCustomHide::AUTO));
     485            4 :     case P_TYPE::MARKER_TYPE:
     486            4 :         return PropertyValue(TConv::fromXml(e.readAsciiText(), MarkerType::USER));
     487            0 :     default:
     488            0 :         ASSERT_X("unhandled PID type");
     489              :         break;
     490              :     }
     491              :     return PropertyValue();
     492              : }
     493              : 
     494       247173 : bool TRead::readProperty(EngravingItem* item, const AsciiStringView& tag, XmlReader& xml, ReadContext& ctx, Pid pid)
     495              : {
     496       247173 :     if (tag == propertyName(pid)) {
     497         1103 :         readProperty(item, xml, ctx, pid);
     498         1103 :         return true;
     499              :     }
     500       246070 :     return false;
     501              : }
     502              : 
     503         1657 : void TRead::readProperty(EngravingItem* item, XmlReader& xml, ReadContext& ctx, Pid pid)
     504              : {
     505         1657 :     double spatium = ctx.score() ? ctx.spatium() : item->spatium();
     506         1657 :     PropertyValue v = readPropertyValue(pid, xml, ctx);
     507         1657 :     switch (propertyType(pid)) {
     508            0 :     case P_TYPE::ABSOLUTE: //! NOTE type mm, but stored in xml as spatium
     509            0 :         v = v.value<Spatium>().toAbsolute(spatium);
     510            0 :         break;
     511          173 :     case P_TYPE::POINT:
     512          173 :         if (item->offsetIsSpatiumDependent()) {
     513          173 :             v = v.value<PointF>() * spatium;
     514              :         } else {
     515            0 :             v = v.value<PointF>() * DPMM;
     516              :         }
     517          173 :         break;
     518         1484 :     default:
     519         1484 :         break;
     520              :     }
     521              : 
     522              :     // Pre-4.4 compatibility: these items now use DIRECTION property
     523         1657 :     if (pid == Pid::PLACEMENT && item->hasVoiceAssignmentProperties()) {
     524            0 :         pid = Pid::DIRECTION;
     525            0 :         v = v.value<PlacementV>() == PlacementV::ABOVE ? PropertyValue(DirectionV::UP) : PropertyValue(DirectionV::DOWN);
     526              :     }
     527              : 
     528         1657 :     if (pid == Pid::OFFSET && ctx.mscVersion() < 500) {
     529            0 :         compat::CompatUtils::migrateOffset500(item, v);
     530              :     }
     531              : 
     532         1657 :     if (!ctx.shouldSkipProperty(pid)) {
     533         1657 :         item->setProperty(pid, v);
     534         1657 :         if (item->isStyled(pid)) {
     535          417 :             item->setPropertyFlags(pid, PropertyFlags::UNSTYLED);
     536              :         }
     537              :     }
     538         1657 : }
     539              : 
     540        24690 : bool TRead::readStyledProperty(EngravingItem* item, const AsciiStringView& tag, XmlReader& xml, ReadContext& ctx)
     541              : {
     542        91312 :     for (const StyledProperty& spp : *item->styledProperties()) {
     543        66728 :         if (readProperty(item, tag, xml, ctx, spp.pid)) {
     544          106 :             return true;
     545              :         }
     546              :     }
     547        24584 :     return false;
     548              : }
     549              : 
     550        21783 : bool TRead::readItemProperties(EngravingItem* item, XmlReader& e, ReadContext& ctx)
     551              : {
     552        21783 :     const AsciiStringView tag(e.name());
     553              : 
     554        21783 :     if (tag == "eid") {
     555        18053 :         readItemEID(item, e, ctx);
     556         3730 :     } else if (TRead::readProperty(item, tag, e, ctx, Pid::SIZE_SPATIUM_DEPENDENT)) {
     557         3603 :     } else if (TRead::readProperty(item, tag, e, ctx, Pid::OFFSET)) {
     558         3569 :     } else if (TRead::readProperty(item, tag, e, ctx, Pid::MIN_DISTANCE)) {
     559         3569 :     } else if (TRead::readProperty(item, tag, e, ctx, Pid::AUTOPLACE)) {
     560         3562 :     } else if (tag == "track") {
     561          581 :         item->setTrack(e.readInt() + ctx.trackOffset());
     562         2981 :     } else if (tag == "color") {
     563           10 :         item->setColor(e.readColor());
     564         2971 :     } else if (tag == "visible") {
     565            1 :         item->setVisible(e.readInt());
     566         2970 :     } else if (tag == "linkedTo") {
     567         2897 :         readItemLink(item, e, ctx);
     568           73 :     } else if (TRead::readProperty(item, tag, e, ctx, Pid::POSITION_LINKED_TO_MASTER)) {
     569           73 :     } else if (TRead::readProperty(item, tag, e, ctx, Pid::APPEARANCE_LINKED_TO_MASTER)) {
     570           73 :     } else if (TRead::readProperty(item, tag, e, ctx, Pid::EXCLUDE_FROM_OTHER_PARTS)) {
     571           73 :     } else if (tag == "voice") {
     572            0 :         item->setVoice(e.readInt());
     573           73 :     } else if (tag == "tag") {
     574            0 :         e.skipCurrentElement();
     575           73 :     } else if (TRead::readProperty(item, tag, e, ctx, Pid::PLACEMENT)) {
     576           59 :     } else if (tag == "z") {
     577            4 :         item->setZ(e.readInt());
     578           55 :     } else if (TRead::readProperty(item, tag, e, ctx, Pid::HAS_PARENTHESES)) {
     579           52 :     } else if (tag == "Parenthesis") {
     580            0 :         Parenthesis* p = Factory::createParenthesis(item);
     581            0 :         TRead::read(p, e, ctx);
     582            0 :         p->setTrack(ctx.track());
     583            0 :         item->add(p);
     584              :     } else {
     585           52 :         return false;
     586              :     }
     587        21731 :     return true;
     588              : }
     589              : 
     590         3098 : static Spanner* tryCreateSpanner(const AsciiStringView& tag, ReadContext& ctx, bool requireNoteAnchor)
     591              : {
     592         3098 :     ElementType type = TConv::fromXml(tag, ElementType::INVALID);
     593         3098 :     if (type == ElementType::INVALID) {
     594         2984 :         return nullptr;
     595              :     }
     596              : 
     597          114 :     EngravingItem* item = Factory::createItem(type, ctx.dummy());
     598          114 :     if (!item || !item->isSpanner()) {
     599            0 :         delete item;
     600            0 :         return nullptr;
     601              :     }
     602              : 
     603          114 :     Spanner* spanner = toSpanner(item);
     604          114 :     if ((spanner->anchor() == Spanner::Anchor::NOTE) != requireNoteAnchor) {
     605            0 :         delete item;
     606            0 :         return nullptr;
     607              :     }
     608              : 
     609          114 :     return spanner;
     610              : }
     611              : 
     612           42 : void TRead::readScoreSpanners(Score* score, XmlReader& e, ReadContext& ctx)
     613              : {
     614          115 :     while (e.readNextStartElement()) {
     615           73 :         const AsciiStringView tag(e.name());
     616           73 :         if (Spanner* spanner = tryCreateSpanner(tag, ctx, /*requireNoteAnchor*/ false)) {
     617           73 :             TRead::readItem(spanner, e, ctx);
     618           73 :             if (ctx.pasteMode()) {
     619           22 :                 score->undoAddElement(spanner);
     620              :             } else {
     621           51 :                 score->addSpanner(spanner);
     622              :             }
     623              :         } else {
     624            0 :             e.unknown();
     625              :         }
     626              :     }
     627           42 : }
     628              : 
     629        18753 : void TRead::readItemEID(EngravingObject* item, XmlReader& xml, ReadContext& ctx)
     630              : {
     631        18753 :     AsciiStringView s = xml.readAsciiText();
     632        18753 :     EID eid = EID::fromStdString(s);
     633        18753 :     IF_ASSERT_FAILED(eid.isValid()) {
     634         1909 :         return;
     635              :     }
     636              : 
     637        18753 :     if (ctx.pasteMode()) {
     638              :         // On pasting we must create new EIDs for the elements, as the serialized EID is the EID of the item which was copied
     639              :         // This could still be in use elsewhere in the score
     640         1909 :         EID realEid = item->assignNewEID();
     641         1909 :         ctx.registerPastedEID(eid, realEid);
     642         1909 :         return;
     643              :     }
     644              : 
     645        16844 :     item->setEID(eid);
     646              : }
     647              : 
     648         2967 : void TRead::readItemLink(EngravingItem* item, XmlReader& xml, ReadContext& ctx)
     649              : {
     650         2967 :     AsciiStringView s = xml.readAsciiText();
     651         2967 :     EID eid = EID::fromStdString(s);
     652         2967 :     DO_ASSERT(eid.isValid());
     653         2967 :     EIDRegister* eidRegister = ctx.score()->masterScore()->eidRegister();
     654         2967 :     EngravingObject* mainElement = eidRegister->itemFromEID(eid);
     655         2967 :     IF_ASSERT_FAILED(mainElement) {
     656            0 :         LOGE() << "Link failed: Main linked element not found for " << item->typeName() << " at " << ctx.tick().toString();
     657            0 :         return;
     658              :     }
     659         2967 :     IF_ASSERT_FAILED(mainElement->type() == item->type()) {
     660            0 :         LOGE() << "Link failed: Main element type (" << mainElement->typeName() << ") does not match linked item type (" <<
     661            0 :             item->typeName() << ") at " << ctx.tick().toString();
     662            0 :         return;
     663              :     }
     664              : 
     665         2967 :     item->linkTo(mainElement);
     666              : }
     667              : 
     668           15 : void TRead::read(TextBase* t, XmlReader& xml, ReadContext& ctx)
     669              : {
     670           75 :     while (xml.readNextStartElement()) {
     671           45 :         if (!readProperties(toTextBase(t), xml, ctx)) {
     672            0 :             xml.unknown();
     673              :         }
     674              :     }
     675           15 : }
     676              : 
     677          103 : void TRead::read(TempoText* t, XmlReader& e, ReadContext& ctx)
     678              : {
     679              :     /// This property was written in the wrong order from 4.6.0-4.6.2
     680              :     /// It was written before the text style and was reset on initialising the text style
     681          103 :     std::optional<double> symbolSize;
     682              : 
     683          477 :     while (e.readNextStartElement()) {
     684          374 :         const AsciiStringView tag(e.name());
     685          374 :         if (readProperty(t, tag, e, ctx, Pid::PLAY)) {
     686          374 :         } else if (tag == "tempo") {
     687          103 :             t->setTempo(TConv::fromXml(e.readAsciiText(), Constants::DEFAULT_TEMPO));
     688          271 :         } else if (tag == "followText") {
     689            3 :             t->setFollowText(e.readInt());
     690          268 :         } else if (tag == "type") {
     691            2 :             auto type = e.readAsciiText();
     692            2 :             if (type == "aTempo") {
     693            1 :                 t->setTempoTextType(TempoTextType::A_TEMPO);
     694            1 :             } else if (type == "tempoPrimo") {
     695            1 :                 t->setTempoTextType(TempoTextType::TEMPO_PRIMO);
     696            0 :             } else if (type == "normal") {
     697            0 :                 t->setTempoTextType(TempoTextType::NORMAL);
     698              :             } else {
     699            0 :                 e.unknown();
     700              :             }
     701          266 :         } else if (tag == "musicSymbolSize") {
     702            0 :             symbolSize = e.readDouble();
     703          266 :         } else if (!readProperties(toTextBase(t), e, ctx)) {
     704            0 :             e.unknown();
     705              :         }
     706              :     }
     707              :     // check sanity
     708          103 :     if (t->xmlText().isEmpty()) {
     709            0 :         t->setXmlText(String(u"<sym>metNoteQuarterUp</sym> = %1").arg(int(lrint(t->tempo().toBPM().val))));
     710            0 :         t->setVisible(false);
     711              :     }
     712              : 
     713          103 :     if (symbolSize.has_value()) {
     714            0 :         t->setProperty(Pid::MUSIC_SYMBOL_SIZE, symbolSize.value());
     715            0 :         if (t->isStyled(Pid::MUSIC_SYMBOL_SIZE)) {
     716            0 :             t->setPropertyFlags(Pid::MUSIC_SYMBOL_SIZE, PropertyFlags::UNSTYLED);
     717              :         }
     718              :     }
     719          103 : }
     720              : 
     721           30 : void TRead::read(StaffText* t, XmlReader& xml, ReadContext& ctx)
     722              : {
     723          112 :     while (xml.readNextStartElement()) {
     724           82 :         const AsciiStringView tag(xml.name());
     725           82 :         if (tag == "SoundFlag") {
     726            0 :             SoundFlag* flag = Factory::createSoundFlag(t);
     727            0 :             read(flag, xml, ctx);
     728            0 :             t->setSoundFlag(flag);
     729           82 :         } else if (!readProperties(static_cast<StaffTextBase*>(t), xml, ctx)) {
     730            0 :             xml.unknown();
     731              :         }
     732              :     }
     733           30 : }
     734              : 
     735            0 : void TRead::read(StaveSharingLabel* t, XmlReader& xml, ReadContext& ctx)
     736              : {
     737            0 :     while (xml.readNextStartElement()) {
     738            0 :         if (!readProperties(static_cast<StaffTextBase*>(t), xml, ctx)) {
     739            0 :             xml.unknown();
     740              :         }
     741              :     }
     742            0 : }
     743              : 
     744            1 : void TRead::read(StaffTextBase* t, XmlReader& xml, ReadContext& ctx)
     745              : {
     746            1 :     t->clear();
     747              : 
     748              :     /// This property was written in the wrong order from 4.6.0-4.6.2
     749              :     /// It was written before the text style and was reset on initialising the text style
     750            1 :     std::optional<double> symbolSize;
     751              : 
     752            5 :     while (xml.readNextStartElement()) {
     753            4 :         const AsciiStringView tag(xml.name());
     754              : 
     755            4 :         if (tag == "musicSymbolSize") {
     756            0 :             symbolSize = xml.readDouble();
     757            4 :         } else if (!readProperties(t, xml, ctx)) {
     758            0 :             xml.unknown();
     759              :         }
     760              :     }
     761              : 
     762            1 :     if (symbolSize.has_value()) {
     763            0 :         t->setProperty(Pid::MUSIC_SYMBOL_SIZE, symbolSize.value());
     764            0 :         if (t->isStyled(Pid::MUSIC_SYMBOL_SIZE)) {
     765            0 :             t->setPropertyFlags(Pid::MUSIC_SYMBOL_SIZE, PropertyFlags::UNSTYLED);
     766              :         }
     767              :     }
     768            1 : }
     769              : 
     770           86 : bool TRead::readProperties(StaffTextBase* t, XmlReader& e, ReadContext& ctx)
     771              : {
     772           86 :     const AsciiStringView tag(e.name());
     773              : 
     774           86 :     if (tag == "MidiAction") {
     775            0 :         int channel = e.intAttribute("channel", 0);
     776            0 :         String name = e.attribute("name");
     777            0 :         bool found = false;
     778            0 :         size_t n = t->channelActions().size();
     779            0 :         for (size_t i = 0; i < n; ++i) {
     780            0 :             ChannelActions* a = &t->channelActions()[i];
     781            0 :             if (a->channel == channel) {
     782            0 :                 a->midiActionNames.append(name);
     783            0 :                 found = true;
     784            0 :                 break;
     785              :             }
     786              :         }
     787            0 :         if (!found) {
     788            0 :             ChannelActions a;
     789            0 :             a.channel = channel;
     790            0 :             a.midiActionNames.append(name);
     791            0 :             t->channelActions().push_back(a);
     792            0 :         }
     793            0 :         e.readNext();
     794           86 :     } else if (tag == "channelSwitch" || tag == "articulationChange") {
     795            0 :         voice_idx_t voice = static_cast<voice_idx_t>(e.intAttribute("voice", -1));
     796            0 :         if (voice < VOICES) {
     797            0 :             t->setChannelName(voice, e.attribute("name"));
     798            0 :         } else if (voice == muse::nidx) {
     799              :             // no voice applies channel to all voices for
     800              :             // compatibility
     801            0 :             for (voice_idx_t i = 0; i < VOICES; ++i) {
     802            0 :                 t->setChannelName(i, e.attribute("name"));
     803              :             }
     804              :         }
     805            0 :         e.readNext();
     806           86 :     } else if (tag == "aeolus") {
     807            0 :         int group = e.intAttribute("group", -1);
     808            0 :         if (group >= 0 && group < 4) {
     809            0 :             t->setAeolusStop(group, e.readInt());
     810              :         } else {
     811            0 :             e.readNext();
     812              :         }
     813            0 :         t->setSetAeolusStops(true);
     814           86 :     } else if (tag == "swing") {
     815            1 :         DurationType swingUnit = TConv::fromXml(e.asciiAttribute("unit"), DurationType::V_INVALID);
     816            1 :         int unit = 0;
     817            1 :         if (swingUnit == DurationType::V_EIGHTH) {
     818            1 :             unit = Constants::DIVISION / 2;
     819            0 :         } else if (swingUnit == DurationType::V_16TH) {
     820            0 :             unit = Constants::DIVISION / 4;
     821            0 :         } else if (swingUnit == DurationType::V_ZERO) {
     822            0 :             unit = 0;
     823              :         }
     824            1 :         int ratio = e.intAttribute("ratio", 60);
     825            1 :         t->setSwing(true);
     826            1 :         t->setSwingParameters(unit, ratio);
     827            1 :         e.readNext();
     828           85 :     } else if (tag == "capo") {
     829            0 :         int fretId = e.intAttribute("fretId", 0);
     830            0 :         t->setCapo(fretId);
     831            0 :         e.readNext();
     832           85 :     } else if (!readProperties(toTextBase(t), e, ctx)) {
     833            0 :         return false;
     834              :     }
     835           86 :     return true;
     836              : }
     837              : 
     838          112 : void TRead::read(Dynamic* d, XmlReader& e, ReadContext& ctx)
     839              : {
     840          310 :     while (e.readNextStartElement()) {
     841          198 :         const AsciiStringView tag = e.name();
     842          198 :         if (tag == "subtype") {
     843          112 :             d->setDynamicType(e.readText());
     844           86 :         } else if (tag == "velocity") {
     845           28 :             d->setVelocity(e.readInt());
     846           58 :         } else if (tag == "veloChange") {
     847            0 :             d->setChangeInVelocity(e.readInt());
     848           58 :         } else if (tag == "veloChangeSpeed") {
     849            0 :             d->setVelChangeSpeed(TConv::fromXml(e.readAsciiText(), DynamicSpeed::NORMAL));
     850           58 :         } else if (tag == "play") {
     851            0 :             d->setPlayDynamic(e.readBool());
     852           58 :         } else if (ctx.mscVersion() < 470 && tag == "dynamicsSize") {
     853            0 :             readProperty(d, e, ctx, Pid::MUSICAL_SYMBOLS_SCALE);
     854           58 :         } else if (readProperty(d, tag, e, ctx, Pid::AVOID_BARLINES)) {
     855           52 :         } else if (readProperty(d, tag, e, ctx, Pid::CENTER_ON_NOTEHEAD)) {
     856           52 :         } else if (readProperty(d, tag, e, ctx, Pid::ANCHOR_TO_END_OF_PREVIOUS)) {
     857           52 :         } else if (!readProperties(toTextBase(d), e, ctx)) {
     858            0 :             e.unknown();
     859              :         }
     860              :     }
     861          112 : }
     862              : 
     863            0 : void TRead::read(Expression* expr, XmlReader& xml, ReadContext& ctx)
     864              : {
     865            0 :     while (xml.readNextStartElement()) {
     866            0 :         const AsciiStringView tag = xml.name();
     867            0 :         if (tag == "snapToDynamics") {
     868            0 :             readProperty(expr, xml, ctx, Pid::SNAP_TO_DYNAMICS);
     869            0 :         } else if (!readProperties(toTextBase(expr), xml, ctx)) {
     870            0 :             xml.unknown();
     871              :         }
     872              :     }
     873            0 : }
     874              : 
     875            0 : void TRead::read(FretDiagram* d, XmlReader& e, ReadContext& ctx)
     876              : {
     877            0 :     while (e.readNextStartElement()) {
     878            0 :         const AsciiStringView tag(e.name());
     879              : 
     880            0 :         if (tag == "fretDiagram") {
     881            0 :             while (e.readNextStartElement()) {
     882            0 :                 const AsciiStringView tag2(e.name());
     883              : 
     884            0 :                 if (tag2 == "string") {
     885            0 :                     int no = e.intAttribute("no");
     886            0 :                     while (e.readNextStartElement()) {
     887            0 :                         const AsciiStringView t(e.name());
     888            0 :                         if (t == "dot") {
     889            0 :                             int fret = e.intAttribute("fret", 0);
     890            0 :                             FretDotType dtype = FretItem::nameToDotType(e.readText());
     891            0 :                             d->setDot(no, fret, true, dtype);
     892            0 :                         } else if (t == "marker") {
     893            0 :                             FretMarkerType mtype = FretItem::nameToMarkerType(e.readText());
     894            0 :                             d->setMarker(no, mtype);
     895            0 :                         } else if (t == "fingering") {
     896            0 :                             e.readText();
     897              :                             /*setFingering(no, e.readInt()); NOTE:JT todo */
     898              :                         } else {
     899            0 :                             e.unknown();
     900              :                         }
     901              :                     }
     902            0 :                 } else if (tag2 == "barre") {
     903            0 :                     int start = e.intAttribute("start", -1);
     904            0 :                     int end = e.intAttribute("end", -1);
     905            0 :                     int fret = e.readInt();
     906              : 
     907            0 :                     d->setBarre(start, end, fret);
     908            0 :                 } else if (!readItemProperties(d, e, ctx)) {
     909            0 :                     e.unknown();
     910              :                 }
     911              :             }
     912            0 :         } else if (tag == "showNut") {
     913            0 :             TRead::readProperty(d, e, ctx, Pid::FRET_NUT);
     914            0 :         } else if (tag == "orientation") {
     915            0 :             TRead::readProperty(d, e, ctx, Pid::ORIENTATION);
     916            0 :         } else if (tag == "strings") {
     917            0 :             TRead::readProperty(d, e, ctx, Pid::FRET_STRINGS);
     918            0 :         } else if (tag == "frets") {
     919            0 :             TRead::readProperty(d, e, ctx, Pid::FRET_FRETS);
     920            0 :         } else if (tag == "fretOffset") {
     921            0 :             TRead::readProperty(d, e, ctx, Pid::FRET_OFFSET);
     922            0 :         } else if (tag == "mag") {
     923            0 :             TRead::readProperty(d, e, ctx, Pid::MAG);
     924            0 :         } else if (tag == "Harmony") {
     925            0 :             Harmony* h = new Harmony(d->score()->dummy());
     926            0 :             read(h, e, ctx);
     927            0 :             if (h->chords().empty()) {
     928              :                 // Invalid harmony
     929            0 :                 delete h;
     930              :             } else {
     931            0 :                 d->add(h);
     932              :             }
     933            0 :         } else if (readProperty(d, tag, e, ctx, Pid::FRET_SHOW_FINGERINGS)) {
     934            0 :         } else if (readProperty(d, tag, e, ctx, Pid::FRET_FINGERING)) {
     935            0 :         } else if (TRead::readProperty(d, tag, e, ctx, Pid::EXCLUDE_VERTICAL_ALIGN)) {
     936            0 :         } else if (!readItemProperties(d, e, ctx)) {
     937            0 :             e.unknown();
     938              :         }
     939              :     }
     940            0 : }
     941              : 
     942            0 : void TRead::read(TremoloBar* b, XmlReader& e, ReadContext& ctx)
     943              : {
     944            0 :     while (e.readNextStartElement()) {
     945            0 :         auto tag = e.name();
     946            0 :         if (tag == "point") {
     947            0 :             PitchValue pv;
     948            0 :             pv.time    = e.intAttribute("time");
     949            0 :             pv.pitch   = e.intAttribute("pitch");
     950            0 :             pv.vibrato = e.intAttribute("vibrato");
     951            0 :             b->points().push_back(pv);
     952            0 :             e.readNext();
     953            0 :         } else if (tag == "mag") {
     954            0 :             b->setUserMag(e.readDouble(0.1, 10.0));
     955            0 :         } else if (TRead::readStyledProperty(b, tag, e, ctx)) {
     956            0 :         } else if (tag == "play") {
     957            0 :             b->setPlay(e.readInt());
     958            0 :         } else if (TRead::readProperty(b, tag, e, ctx, Pid::LINE_WIDTH)) {
     959            0 :         } else if (!readItemProperties(b, e, ctx)) {
     960            0 :             e.unknown();
     961              :         }
     962              :     }
     963            0 : }
     964              : 
     965           15 : void TRead::read(Sticking* s, XmlReader& xml, ReadContext& ctx)
     966              : {
     967           15 :     read(toTextBase(s), xml, ctx);
     968           15 : }
     969              : 
     970            1 : void TRead::read(SystemText* t, XmlReader& xml, ReadContext& ctx)
     971              : {
     972            1 :     read(static_cast<StaffTextBase*>(t), xml, ctx);
     973            1 : }
     974              : 
     975            0 : void TRead::read(PlayCountText* t, XmlReader& xml, ReadContext& ctx)
     976              : {
     977            0 :     while (xml.readNextStartElement()) {
     978            0 :         const AsciiStringView tag(xml.name());
     979              : 
     980            0 :         if (TRead::readProperty(t, tag, xml, ctx, Pid::PLAY_COUNT_TEXT_SETTING)) {
     981            0 :         } else if (TRead::readProperty(t, tag, xml, ctx, Pid::PLAY_COUNT_TEXT)) {
     982            0 :         } else if (!readProperties(toTextBase(t), xml, ctx)) {
     983            0 :             xml.unknown();
     984              :         }
     985              :     }
     986            0 : }
     987              : 
     988            0 : void TRead::read(PlayTechAnnotation* a, XmlReader& xml, ReadContext& ctx)
     989              : {
     990            0 :     while (xml.readNextStartElement()) {
     991            0 :         const AsciiStringView tag(xml.name());
     992              : 
     993            0 :         if (TRead::readProperty(a, tag, xml, ctx, Pid::PLAY_TECH_TYPE)) {
     994            0 :         } else if (TRead::readProperty(a, tag, xml, ctx, Pid::PLAY)) {
     995            0 :         } else if (!readProperties(toStaffTextBase(a), xml, ctx)) {
     996            0 :             xml.unknown();
     997              :         }
     998              :     }
     999            0 : }
    1000              : 
    1001            0 : void TRead::read(RehearsalMark* m, XmlReader& xml, ReadContext& ctx)
    1002              : {
    1003            0 :     read(toTextBase(m), xml, ctx);
    1004            0 : }
    1005              : 
    1006          364 : void TRead::read(Instrument* item, XmlReader& e, ReadContext& ctx, Part* part)
    1007              : {
    1008          364 :     bool customDrumset = false;
    1009          364 :     bool readSingleNoteDynamics = false;
    1010              : 
    1011          364 :     item->clearChannels();         // remove default channel
    1012          364 :     item->setId(e.attribute("id"));
    1013         4354 :     while (e.readNextStartElement()) {
    1014         3990 :         const AsciiStringView tag(e.name());
    1015         3990 :         if (tag == "singleNoteDynamics") {
    1016            0 :             item->setSingleNoteDynamics(e.readBool());
    1017            0 :             readSingleNoteDynamics = true;
    1018         3990 :         } else if (!readProperties(item, e, ctx, part, &customDrumset)) {
    1019            0 :             e.unknown();
    1020              :         }
    1021              :     }
    1022              : 
    1023          364 :     item->updateInstrumentId();
    1024              : 
    1025          364 :     if (item->channel().empty()) { // for backward compatibility
    1026            4 :         InstrChannel* fallbackChannel = new InstrChannel;
    1027            4 :         fallbackChannel->setName(String::fromUtf8(InstrChannel::DEFAULT_NAME));
    1028            4 :         fallbackChannel->setProgram(item->recognizeMidiProgram());
    1029            4 :         item->appendChannel(fallbackChannel);
    1030          360 :     } else if (item->channel(0)->program() == -1) {
    1031            6 :         item->channel(0)->setProgram(item->recognizeMidiProgram());
    1032              :     }
    1033              : 
    1034          364 :     if (!readSingleNoteDynamics) {
    1035          364 :         item->setSingleNoteDynamicsFromTemplate();
    1036              :     }
    1037          364 : }
    1038              : 
    1039         3990 : bool TRead::readProperties(Instrument* item, XmlReader& e, ReadContext& ctx, Part* part, bool* customDrumset)
    1040              : {
    1041         3990 :     PartAudioSettingsCompat partAudioSetting;
    1042         3990 :     InstrumentTrackId trackId;
    1043         3990 :     if (part && part->score()) {
    1044        11916 :         trackId = { part->score()->parts().size() + 1, item->id() };//part is not assigned to score, _id field is not correct
    1045              :     }
    1046         3990 :     partAudioSetting.instrumentId = trackId;
    1047              : 
    1048         3990 :     const AsciiStringView tag(e.name());
    1049         3990 :     if (tag == "soundId") {
    1050            0 :         item->setSoundId(e.readText());
    1051         3990 :     } else if (tag == "longName") {
    1052           80 :         item->setLongName(readLegacyStaffName(e)); // Old implementation
    1053         3910 :     } else if (tag == "shortName") {
    1054           70 :         item->setShortName(readLegacyStaffName(e)); // Old implementation
    1055         3840 :     } else if (tag == "InstrumentLabel") {
    1056          257 :         readInstrumentLabel(item->instrumentLabel(), e); // New implementation
    1057         3583 :     } else if (tag == "trackName") {
    1058          364 :         item->setTrackName(e.readText());
    1059         3219 :     } else if (tag == "minPitchA") {
    1060          338 :         item->setMinPitchA(e.readInt());
    1061         2881 :     } else if (tag == "minPitchP") {
    1062          338 :         item->setMinPitchP(e.readInt());
    1063         2543 :     } else if (tag == "maxPitchA") {
    1064          338 :         item->setMaxPitchA(e.readInt());
    1065         2205 :     } else if (tag == "maxPitchP") {
    1066          338 :         item->setMaxPitchP(e.readInt());
    1067         1867 :     } else if (tag == "transposeChromatic") {
    1068            7 :         Interval transpose = item->transpose();
    1069            7 :         transpose.chromatic = e.readInt();
    1070            7 :         item->setTranspose(transpose);
    1071         1860 :     } else if (tag == "transposeDiatonic") {
    1072            7 :         Interval transpose = item->transpose();
    1073            7 :         transpose.diatonic = e.readInt();
    1074            7 :         item->setTranspose(transpose);
    1075         1853 :     } else if (tag == "instrumentId") {
    1076          354 :         item->setMusicXmlId(e.readText());
    1077         1499 :     } else if (tag == "useDrumset") {
    1078            0 :         item->setUseDrumset(e.readInt());
    1079            0 :         if (item->useDrumset()) {
    1080            0 :             item->setDrumset(new Drumset(*smDrumset));
    1081              :         }
    1082         1499 :     } else if (tag == "Drum") {
    1083              :         // if we see one of this tags, a custom drumset will be created
    1084            0 :         if (!item->drumset()) {
    1085            0 :             item->setDrumset(new Drumset(*smDrumset));
    1086              :         }
    1087            0 :         if (!(*customDrumset)) {
    1088            0 :             const_cast<Drumset*>(item->drumset())->clear();
    1089            0 :             *customDrumset = true;
    1090              :         }
    1091            0 :         const_cast<Drumset*>(item->drumset())->loadDrum(e);
    1092         1499 :     } else if (tag == "percussionPanelColumns") {
    1093              :         // if we see one of these tags, a custom drumset will be created
    1094            0 :         if (!item->drumset()) {
    1095            0 :             item->setDrumset(new Drumset(*smDrumset));
    1096              :         }
    1097            0 :         if (!(*customDrumset)) {
    1098            0 :             const_cast<Drumset*>(item->drumset())->clear();
    1099            0 :             *customDrumset = true;
    1100              :         }
    1101            0 :         item->drumset()->setPercussionPanelColumns(e.readInt());
    1102              :     }
    1103              :     // support tag "Tablature" for a while for compatibility with existent 2.0 scores
    1104         1499 :     else if (tag == "Tablature" || tag == "StringData") {
    1105            2 :         StringData sd;
    1106            2 :         read(&sd, e);
    1107            2 :         item->setStringData(sd);
    1108         1499 :     } else if (tag == "MidiAction") {
    1109            0 :         NamedEventList a;
    1110            0 :         read(&a, e);
    1111            0 :         item->addMidiAction(a);
    1112         1497 :     } else if (tag == "Articulation") {
    1113         1106 :         MidiArticulation a;
    1114         1106 :         read(&a, e);
    1115         1106 :         item->addMidiArticulation(a);
    1116         1497 :     } else if (tag == "Channel" || tag == "channel") {
    1117          376 :         InstrChannel* a = new InstrChannel;
    1118          376 :         read(a, e, ctx, part, trackId);
    1119          376 :         item->appendChannel(a);
    1120           15 :     } else if (tag == "clef") {           // sets both transposing and concert clef
    1121           15 :         int idx = e.intAttribute("staff", 1) - 1;
    1122           15 :         ClefType ct = TConv::fromXml(e.readAsciiText(), ClefType::G);
    1123           15 :         item->setClefType(idx, ClefTypeList(ct, ct));
    1124            0 :     } else if (tag == "concertClef") {
    1125            0 :         int idx = e.intAttribute("staff", 1) - 1;
    1126            0 :         item->setClefType(idx, ClefTypeList(TConv::fromXml(e.readAsciiText(), ClefType::G), item->clefType(idx).transposingClef));
    1127            0 :     } else if (tag == "transposingClef") {
    1128            0 :         int idx = e.intAttribute("staff", 1) - 1;
    1129            0 :         item->setClefType(idx, ClefTypeList(item->clefType(idx).concertClef, TConv::fromXml(e.readAsciiText(), ClefType::G)));
    1130            0 :     } else if (tag == "glissandoStyle") {
    1131            0 :         item->setGlissandoStyle(TConv::fromXml(e.readAsciiText(), GlissandoStyle::CHROMATIC));
    1132              :     } else {
    1133            0 :         return false;
    1134              :     }
    1135              : 
    1136         3990 :     return true;
    1137        11934 : }
    1138              : 
    1139          376 : void TRead::read(InstrChannel* item, XmlReader& e, ReadContext& ctx, Part* part, const InstrumentTrackId& instrId)
    1140              : {
    1141          376 :     item->setNotifyAboutChangedEnabled(false);
    1142              : 
    1143              :     // synti = 0;
    1144          376 :     item->setName(e.attribute("name"));
    1145          376 :     if (item->name() == "") {
    1146          360 :         item->setName(String::fromUtf8(InstrChannel::DEFAULT_NAME));
    1147              :     }
    1148              : 
    1149          376 :     int midiPort = -1;
    1150          376 :     int midiChannel = -1;
    1151          376 :     PartAudioSettingsCompat partAudioSetting;
    1152          376 :     partAudioSetting.instrumentId = instrId;
    1153              : 
    1154          822 :     while (e.readNextStartElement()) {
    1155          446 :         const AsciiStringView tag(e.name());
    1156          446 :         if (tag == "program") {
    1157          367 :             item->setProgram(e.intAttribute("value", -1));
    1158          367 :             if (item->program() == -1) {
    1159            0 :                 item->setProgram(e.readInt());
    1160              :             } else {
    1161          367 :                 e.readNext();
    1162              :             }
    1163           79 :         } else if (tag == "controller") {
    1164            6 :             int value = e.intAttribute("value", 0);
    1165            6 :             int ctrl  = e.intAttribute("ctrl", 0);
    1166            6 :             switch (ctrl) {
    1167            2 :             case CTRL_HBANK:
    1168            2 :                 item->setBank((value << 7) + (item->bank() & 0x7f));
    1169            2 :                 item->setUserBankController(true);
    1170            2 :                 break;
    1171            2 :             case CTRL_LBANK:
    1172            2 :                 item->setBank((item->bank() & ~0x7f) + (value & 0x7f));
    1173            2 :                 item->setUserBankController(true);
    1174            2 :                 break;
    1175            0 :             case CTRL_VOLUME:
    1176            0 :                 item->setVolume(value);
    1177            0 :                 break;
    1178            2 :             case CTRL_PANPOT:
    1179            2 :                 item->setPan(value);
    1180            2 :                 break;
    1181            0 :             case CTRL_CHORUS_SEND:
    1182            0 :                 item->setChorus(value);
    1183            0 :                 break;
    1184            0 :             case CTRL_REVERB_SEND:
    1185            0 :                 item->setReverb(value);
    1186            0 :                 break;
    1187            0 :             default:
    1188              :             {
    1189            0 :                 Event ev(ME_CONTROLLER);
    1190            0 :                 ev.setOntime(-1);
    1191            0 :                 ev.setChannel(0);
    1192            0 :                 ev.setDataA(ctrl);
    1193            0 :                 ev.setDataB(value);
    1194            0 :                 item->addToInit(ev);
    1195            0 :             }
    1196            0 :             break;
    1197              :             }
    1198            6 :             e.readNext();
    1199           73 :         } else if (tag == "Articulation") {
    1200            0 :             MidiArticulation a;
    1201            0 :             read(&a, e);
    1202            0 :             item->articulation.push_back(a);
    1203           73 :         } else if (tag == "MidiAction") {
    1204            0 :             NamedEventList a;
    1205            0 :             read(&a, e);
    1206            0 :             item->midiActions.push_back(a);
    1207           73 :         } else if (tag == "synti") {
    1208           45 :             item->setSynti(e.readText());
    1209           28 :         } else if (tag == "color") {
    1210            0 :             item->setColor(e.readInt());
    1211           28 :         } else if (tag == "mute") {
    1212            0 :             partAudioSetting.mute = e.readInt();
    1213           28 :         } else if (tag == "solo") {
    1214            0 :             partAudioSetting.solo = e.readInt();
    1215           28 :         } else if (tag == "midiPort") {
    1216           14 :             midiPort = e.readInt();
    1217           14 :         } else if (tag == "midiChannel") {
    1218           14 :             midiChannel = e.readInt();
    1219              :         } else {
    1220            0 :             e.unknown();
    1221              :         }
    1222              :     }
    1223              : 
    1224          376 :     item->setMustUpdateInit(true);
    1225              : 
    1226          376 :     ctx.addPartAudioSettingCompat(partAudioSetting);
    1227              : 
    1228          376 :     item->setNotifyAboutChangedEnabled(true);
    1229              : 
    1230          376 :     if ((midiPort != -1 || midiChannel != -1) && part && part->score()->isMaster()) {
    1231           12 :         part->masterScore()->addMidiMapping(item, part, midiPort, midiChannel);
    1232              :     }
    1233          376 : }
    1234              : 
    1235         1106 : void TRead::read(MidiArticulation* item, XmlReader& e)
    1236              : {
    1237         1106 :     item->name = e.attribute("name");
    1238         3318 :     while (e.readNextStartElement()) {
    1239         2212 :         const AsciiStringView tag(e.name());
    1240         2212 :         if (tag == "velocity") {
    1241         1106 :             String text(e.readText());
    1242         1106 :             if (text.endsWith(u"%")) {
    1243            0 :                 text = text.left(text.size() - 1);
    1244              :             }
    1245         1106 :             item->velocity = text.toInt();
    1246         2212 :         } else if (tag == "gateTime") {
    1247         1106 :             String text(e.readText());
    1248         1106 :             if (text.endsWith(u"%")) {
    1249            0 :                 text = text.left(text.size() - 1);
    1250              :             }
    1251         1106 :             item->gateTime = text.toInt();
    1252         1106 :         } else if (tag == "descr") {
    1253            0 :             item->descr = e.readText();
    1254              :         } else {
    1255            0 :             e.unknown();
    1256              :         }
    1257              :     }
    1258         1106 : }
    1259              : 
    1260            0 : void TRead::read(NamedEventList* item, XmlReader& e)
    1261              : {
    1262            0 :     item->name = e.attribute("name");
    1263            0 :     while (e.readNextStartElement()) {
    1264            0 :         const AsciiStringView tag(e.name());
    1265            0 :         if (tag == "program") {
    1266            0 :             MidiCoreEvent ev(ME_CONTROLLER, 0, CTRL_PROGRAM, e.intAttribute("value", 0));
    1267            0 :             item->events.push_back(ev);
    1268            0 :             e.skipCurrentElement();
    1269            0 :         } else if (tag == "controller") {
    1270            0 :             MidiCoreEvent ev;
    1271            0 :             ev.setType(ME_CONTROLLER);
    1272            0 :             ev.setDataA(e.intAttribute("ctrl", 0));
    1273            0 :             ev.setDataB(e.intAttribute("value", 0));
    1274            0 :             item->events.push_back(ev);
    1275            0 :             e.skipCurrentElement();
    1276            0 :         } else if (tag == "descr") {
    1277            0 :             item->descr = e.readText();
    1278              :         } else {
    1279            0 :             e.unknown();
    1280              :         }
    1281              :     }
    1282            0 : }
    1283              : 
    1284            6 : void TRead::read(InstrumentChange* c, XmlReader& e, ReadContext& ctx)
    1285              : {
    1286            6 :     Instrument inst;
    1287           27 :     while (e.readNextStartElement()) {
    1288           21 :         const AsciiStringView tag(e.name());
    1289           21 :         if (tag == "Instrument") {
    1290            6 :             read(&inst, e, ctx, c->part());
    1291           15 :         } else if (tag == "init") {
    1292            6 :             c->setInit(e.readBool());
    1293            9 :         } else if (!readProperties(toTextBase(c), e, ctx)) {
    1294            0 :             e.unknown();
    1295              :         }
    1296              :     }
    1297              : 
    1298            6 :     c->setInstrument(inst);
    1299            6 : }
    1300              : 
    1301            0 : void TRead::read(KeyList* item, XmlReader& e, ReadContext& ctx)
    1302              : {
    1303            0 :     while (e.readNextStartElement()) {
    1304            0 :         if (e.name() == "key") {
    1305              :             Key k;
    1306            0 :             int tick = e.intAttribute("tick", 0);
    1307            0 :             if (e.hasAttribute("custom")) {
    1308            0 :                 k = Key::C;              // ke.setCustomType(e.intAttribute("custom"));
    1309              :             } else {
    1310            0 :                 k = Key(e.intAttribute("idx"));
    1311              :             }
    1312            0 :             KeySigEvent ke;
    1313            0 :             ke.setConcertKey(k);
    1314            0 :             (*item)[ctx.fileDivision(tick)] = ke;
    1315            0 :             e.readNext();
    1316            0 :         } else {
    1317            0 :             e.unknown();
    1318              :         }
    1319              :     }
    1320            0 : }
    1321              : 
    1322           74 : void TRead::read(KeySig* s, XmlReader& e, ReadContext& ctx)
    1323              : {
    1324           74 :     KeySigEvent sig;
    1325           74 :     int subtype = 0;
    1326           74 :     Part* p = s->part();
    1327              : 
    1328          220 :     while (e.readNextStartElement()) {
    1329          146 :         const AsciiStringView tag(e.name());
    1330          146 :         if (tag == "CustDef") {
    1331            0 :             CustDef cd;
    1332            0 :             while (e.readNextStartElement()) {
    1333            0 :                 const AsciiStringView t(e.name());
    1334            0 :                 if (t == "sym") {
    1335            0 :                     AsciiStringView val(e.readAsciiText());
    1336              :                     bool valid;
    1337            0 :                     SymId id = SymId(val.toInt(&valid));
    1338            0 :                     if (!valid) {
    1339            0 :                         id = SymNames::symIdByName(val);
    1340              :                     }
    1341            0 :                     cd.sym = id;
    1342            0 :                 } else if (t == "def") {
    1343            0 :                     cd.degree = e.intAttribute("degree", 0);
    1344            0 :                     cd.octAlt = e.intAttribute("octAlt", 0);
    1345            0 :                     cd.xAlt = Spatium(e.doubleAttribute("xAlt", 0.0));
    1346            0 :                     e.readNext();
    1347            0 :                 } else if (t == "pos") { // for older files
    1348            0 :                     Spatium prevx = 0_sp;
    1349            0 :                     Spatium accidentalGap = ctx.score()->style().styleS(Sid::keysigAccidentalDistance);
    1350            0 :                     double _spatium = s->spatium();
    1351              :                     // count default x position
    1352            0 :                     for (CustDef& cd2 : sig.customKeyDefs()) {
    1353            0 :                         prevx += Spatium::fromAbsolute(s->symWidth(cd2.sym), _spatium) + accidentalGap + cd2.xAlt;
    1354              :                     }
    1355            0 :                     bool flat = std::string(SymNames::nameForSymId(cd.sym).ascii()).find("Flat") != std::string::npos;
    1356              :                     // if x not there, use default step
    1357            0 :                     cd.xAlt = Spatium(e.doubleAttribute("x", prevx.val())) - prevx;
    1358              :                     // if y not there, use middle line
    1359            0 :                     int line = static_cast<int>(e.doubleAttribute("y", 2) * 2);
    1360            0 :                     cd.degree = (3 - line) % 7;
    1361            0 :                     cd.degree += (cd.degree < 0) ? 7 : 0;
    1362            0 :                     line += flat ? -1 : 1; // top point in treble for # is -1 (gis), and for b is 1 (es)
    1363            0 :                     cd.octAlt = static_cast<int>((line - (line >= 0 ? 0 : 6)) / 7);
    1364            0 :                     e.readNext();
    1365              :                 } else {
    1366            0 :                     e.unknown();
    1367              :                 }
    1368              :             }
    1369            0 :             sig.customKeyDefs().push_back(cd);
    1370          146 :         } else if (TRead::readProperty(s, tag, e, ctx, Pid::SHOW_COURTESY)) {
    1371          146 :         } else if (tag == "concertKey") {
    1372           74 :             sig.setConcertKey(Key(e.readInt()));
    1373           72 :         } else if (tag == "actualKey") {
    1374            5 :             sig.setKey(Key(e.readInt()));
    1375           67 :         } else if (tag == "custom") {
    1376            0 :             e.readInt();
    1377            0 :             sig.setCustom(true);
    1378           67 :         } else if (tag == "mode") {
    1379            0 :             sig.setMode(TConv::fromXml(e.readAsciiText(), KeyMode::UNKNOWN));
    1380           67 :         } else if (tag == "subtype") {
    1381            0 :             subtype = e.readInt();
    1382           67 :         } else if (tag == "forInstrumentChange") {
    1383            5 :             sig.setForInstrumentChange(e.readBool());
    1384           62 :         } else if (TRead::readProperty(s, tag, e, ctx, Pid::IS_COURTESY)) {
    1385           62 :         } else if (!readItemProperties(s, e, ctx)) {
    1386            0 :             e.unknown();
    1387              :         }
    1388              :     }
    1389              :     // for backward compatibility
    1390           74 :     if (!sig.isValid()) {
    1391            0 :         sig.initFromSubtype(subtype);
    1392              :     }
    1393           74 :     if (sig.custom() && sig.customKeyDefs().empty()) {
    1394            0 :         sig.setMode(KeyMode::NONE);
    1395              :     }
    1396              :     // if there are more than 6 accidentals in transposing key, it cannot be PreferSharpFlat::AUTO
    1397           74 :     if (p && !s->concertPitch() && (sig.key() > 6 || sig.key() < -6)
    1398          148 :         && p->preferSharpFlat() == PreferSharpFlat::AUTO && !p->instrument(s->tick())->transpose().isZero()) {
    1399            0 :         p->setPreferSharpFlat(PreferSharpFlat::NONE);
    1400              :     }
    1401              : 
    1402           74 :     s->setKeySigEvent(sig);
    1403           74 : }
    1404              : 
    1405            1 : void TRead::read(LaissezVib* lv, XmlReader& xml, ReadContext& ctx)
    1406              : {
    1407            4 :     while (xml.readNextStartElement()) {
    1408            3 :         const AsciiStringView tag(xml.name());
    1409            3 :         if (TRead::readProperty(lv, tag, xml, ctx, Pid::TIE_PLACEMENT)) {
    1410            3 :         } else if (TRead::readProperty(lv, tag, xml, ctx, Pid::MIN_LENGTH)) {
    1411            3 :         } else if (!readProperties(toSlurTie(lv), xml, ctx)) {
    1412            0 :             xml.unknown();
    1413              :         }
    1414              :     }
    1415            1 : }
    1416              : 
    1417            0 : void TRead::read(StaffState* s, XmlReader& e, ReadContext& ctx)
    1418              : {
    1419            0 :     while (e.readNextStartElement()) {
    1420            0 :         const AsciiStringView tag(e.name());
    1421            0 :         if (tag == "subtype") {
    1422            0 :             s->setStaffStateType(StaffStateType(e.readInt()));
    1423            0 :         } else if (tag == "Instrument") {
    1424            0 :             Instrument i;
    1425            0 :             read(&i, e, ctx, nullptr);
    1426            0 :             s->setInstrument(std::move(i));
    1427            0 :         } else if (!readItemProperties(s, e, ctx)) {
    1428            0 :             e.unknown();
    1429              :         }
    1430              :     }
    1431            0 : }
    1432              : 
    1433            0 : void TRead::read(FiguredBass* b, XmlReader& e, ReadContext& ctx)
    1434              : {
    1435            0 :     String normalizedText;
    1436            0 :     int idx = 0;
    1437            0 :     while (e.readNextStartElement()) {
    1438            0 :         const AsciiStringView tag(e.name());
    1439            0 :         if (tag == "ticks") {
    1440            0 :             b->setTicks(e.readFraction());
    1441            0 :         } else if (tag == "onNote") {
    1442            0 :             b->setOnNote(e.readInt() != 0l);
    1443            0 :         } else if (tag == "FiguredBassItem") {
    1444            0 :             FiguredBassItem* pItem = b->createItem(idx++);
    1445            0 :             pItem->setTrack(b->track());
    1446            0 :             pItem->setOwnershipParent(b);
    1447            0 :             TRead::read(pItem, e, ctx);
    1448            0 :             b->appendItem(pItem);
    1449              :             // add item normalized text
    1450            0 :             if (!normalizedText.isEmpty()) {
    1451            0 :                 normalizedText.append('\n');
    1452              :             }
    1453            0 :             normalizedText.append(pItem->normalizedText());
    1454              :         }
    1455              : //            else if (tag == "style")
    1456              : //                  setStyledPropertyListIdx(e.readElementText());
    1457            0 :         else if (!readProperties(toTextBase(b), e, ctx)) {
    1458            0 :             e.unknown();
    1459              :         }
    1460              :     }
    1461              :     // if items could be parsed set normalized text
    1462            0 :     if (b->items().size() > 0) {
    1463            0 :         b->setXmlText(normalizedText);          // this is the text to show while editing
    1464              :     }
    1465            0 : }
    1466              : 
    1467            0 : void TRead::read(FiguredBassItem* i, XmlReader& e, ReadContext& ctx)
    1468              : {
    1469            0 :     while (e.readNextStartElement()) {
    1470            0 :         const AsciiStringView tag(e.name());
    1471              : 
    1472            0 :         if (tag == "brackets") {
    1473            0 :             i->setParenth1((FiguredBassItem::Parenthesis)e.intAttribute("b0"));
    1474            0 :             i->setParenth2((FiguredBassItem::Parenthesis)e.intAttribute("b1"));
    1475            0 :             i->setParenth3((FiguredBassItem::Parenthesis)e.intAttribute("b2"));
    1476            0 :             i->setParenth4((FiguredBassItem::Parenthesis)e.intAttribute("b3"));
    1477            0 :             i->setParenth5((FiguredBassItem::Parenthesis)e.intAttribute("b4"));
    1478            0 :             e.readNext();
    1479            0 :         } else if (tag == "prefix") {
    1480            0 :             i->setPrefix((FiguredBassItem::Modifier)(e.readInt()));
    1481            0 :         } else if (tag == "digit") {
    1482            0 :             i->setDigit(e.readInt());
    1483            0 :         } else if (tag == "suffix") {
    1484            0 :             i->setSuffix((FiguredBassItem::Modifier)(e.readInt()));
    1485            0 :         } else if (tag == "continuationLine") {
    1486            0 :             i->setContLine((FiguredBassItem::ContLine)(e.readInt()));
    1487            0 :         } else if (!readItemProperties(i, e, ctx)) {
    1488            0 :             e.unknown();
    1489              :         }
    1490              :     }
    1491            0 : }
    1492              : 
    1493            0 : void TRead::read(Excerpt* item, XmlReader& e, ReadContext&)
    1494              : {
    1495            0 :     const std::vector<Part*>& pl = item->masterScore()->parts();
    1496            0 :     std::vector<Part*> parts;
    1497            0 :     while (e.readNextStartElement()) {
    1498            0 :         const AsciiStringView tag = e.name();
    1499            0 :         if (tag == "name" || tag == "title") {
    1500            0 :             item->setName(e.readText().trimmed(), /*saveAndNotify=*/ false);
    1501            0 :         } else if (tag == "part") {
    1502            0 :             size_t partIdx = static_cast<size_t>(e.readInt());
    1503            0 :             if (partIdx >= pl.size()) {
    1504            0 :                 LOGD("Excerpt::read: bad part index");
    1505              :             } else {
    1506            0 :                 parts.push_back(pl.at(partIdx));
    1507              :             }
    1508              :         }
    1509              :     }
    1510            0 :     item->setParts(parts);
    1511            0 : }
    1512              : 
    1513            2 : void TRead::read(Fermata* f, XmlReader& e, ReadContext& ctx)
    1514              : {
    1515            8 :     while (e.readNextStartElement()) {
    1516            4 :         if (!readProperties(f, e, ctx)) {
    1517            0 :             e.unknown();
    1518              :         }
    1519              :     }
    1520            2 : }
    1521              : 
    1522            4 : bool TRead::readProperties(Fermata* f, XmlReader& xml, ReadContext& ctx)
    1523              : {
    1524            4 :     const AsciiStringView tag(xml.name());
    1525              : 
    1526            4 :     if (tag == "subtype") {
    1527            2 :         AsciiStringView s = xml.readAsciiText();
    1528            2 :         SymId id = SymNames::symIdByName(s);
    1529            2 :         f->setSymIdAndTimeStretch(id);
    1530            2 :     } else if (tag == "play") {
    1531            0 :         f->setPlay(xml.readBool());
    1532            2 :     } else if (tag == "timeStretch") {
    1533            0 :         f->setTimeStretch(xml.readDouble());
    1534            2 :     } else if (tag == "offset") {
    1535            0 :         readItemProperties(f, xml, ctx);
    1536            2 :     } else if (readItemProperties(f, xml, ctx)) {
    1537              :     } else {
    1538            0 :         return false;
    1539              :     }
    1540            4 :     return true;
    1541              : }
    1542              : 
    1543            0 : void TRead::read(Image* img, XmlReader& e, ReadContext& ctx)
    1544              : {
    1545            0 :     bool loaded = false;
    1546              : 
    1547            0 :     while (e.readNextStartElement()) {
    1548            0 :         const AsciiStringView tag(e.name());
    1549            0 :         if (tag == "autoScale") {
    1550            0 :             TRead::readProperty(img, e, ctx, Pid::AUTOSCALE);
    1551            0 :         } else if (tag == "size") {
    1552            0 :             TRead::readProperty(img, e, ctx, Pid::SIZE);
    1553            0 :         } else if (tag == "lockAspectRatio") {
    1554            0 :             TRead::readProperty(img, e, ctx, Pid::LOCK_ASPECT_RATIO);
    1555            0 :         } else if (tag == "sizeIsSpatium") {
    1556              :             // setting this using the property Pid::SIZE_IS_SPATIUM breaks, because the
    1557              :             // property setter attempts to maintain a constant size. If we're reading, we
    1558              :             // don't want to do that, because the stored size will be in:
    1559              :             //    absolute if size isn't spatium
    1560              :             //    sp if size is spatium
    1561            0 :             img->setSizeIsSpatium(e.readBool());
    1562            0 :         } else if (tag == "path") {
    1563            0 :             loaded = img->loadFromStore(e.readText().toStdString());
    1564            0 :         } else if (tag == "linkPath") {
    1565            0 :             if (img->configuration()->allowReadingImagesFromOutsideMscz() && !loaded) {
    1566            0 :                 loaded = img->loadFromFile(e.readText());
    1567              :             } else {
    1568            0 :                 e.skipCurrentElement();
    1569              :             }
    1570            0 :         } else if (!TRead::readProperties(img, e, ctx)) {
    1571            0 :             e.unknown();
    1572              :         }
    1573              :     }
    1574              : 
    1575            0 :     compat::CompatUtils::convertPre470ImageSize(img);
    1576            0 : }
    1577              : 
    1578          120 : void TRead::read(Tuplet* t, XmlReader& e, ReadContext& ctx)
    1579              : {
    1580          120 :     Text* number = nullptr;
    1581          120 :     Fraction ratio;
    1582          120 :     TDuration baseLen;
    1583              : 
    1584          711 :     while (e.readNextStartElement()) {
    1585          591 :         const AsciiStringView tag(e.name());
    1586              : 
    1587          591 :         if (TRead::readStyledProperty(t, tag, e, ctx)) {
    1588          547 :         } else if (tag == "bold") { //important that these properties are read after number is created
    1589            0 :             bool val = e.readInt();
    1590            0 :             if (number) {
    1591            0 :                 number->setBold(val);
    1592              :             }
    1593            0 :             if (t->isStyled(Pid::FONT_STYLE)) {
    1594            0 :                 t->setPropertyFlags(Pid::FONT_STYLE, PropertyFlags::UNSTYLED);
    1595              :             }
    1596          547 :         } else if (tag == "italic") {
    1597            0 :             bool val = e.readInt();
    1598            0 :             if (number) {
    1599            0 :                 number->setItalic(val);
    1600              :             }
    1601            0 :             if (t->isStyled(Pid::FONT_STYLE)) {
    1602            0 :                 t->setPropertyFlags(Pid::FONT_STYLE, PropertyFlags::UNSTYLED);
    1603              :             }
    1604          547 :         } else if (tag == "underline") {
    1605            0 :             bool val = e.readInt();
    1606            0 :             if (number) {
    1607            0 :                 number->setUnderline(val);
    1608              :             }
    1609            0 :             if (t->isStyled(Pid::FONT_STYLE)) {
    1610            0 :                 t->setPropertyFlags(Pid::FONT_STYLE, PropertyFlags::UNSTYLED);
    1611              :             }
    1612          547 :         } else if (tag == "strike") {
    1613            0 :             bool val = e.readInt();
    1614            0 :             if (number) {
    1615            0 :                 number->setStrike(val);
    1616              :             }
    1617            0 :             if (t->isStyled(Pid::FONT_STYLE)) {
    1618            0 :                 t->setPropertyFlags(Pid::FONT_STYLE, PropertyFlags::UNSTYLED);
    1619              :             }
    1620          547 :         } else if (tag == "normalNotes") {
    1621          120 :             ratio.setDenominator(e.readInt());
    1622          427 :         } else if (tag == "actualNotes") {
    1623          120 :             ratio.setNumerator(e.readInt());
    1624          307 :         } else if (tag == "p1") {
    1625            0 :             t->setUserPoint1(e.readPoint() * t->style().spatium());
    1626          307 :         } else if (tag == "p2") {
    1627            0 :             t->setUserPoint2(e.readPoint() * t->style().spatium());
    1628          307 :         } else if (tag == "baseNote") {
    1629          120 :             baseLen = TDuration(TConv::fromXml(e.readAsciiText(), DurationType::V_INVALID));
    1630          187 :         } else if (tag == "baseDots") {
    1631            0 :             baseLen.setDots(e.readInt());
    1632          187 :         } else if (tag == "Number") {
    1633          120 :             number = Factory::createText(t, TextStyleType::TUPLET);
    1634          120 :             number->setComposition(true);
    1635          120 :             Tuplet::resetNumberProperty(number);
    1636          120 :             TRead::read(number, e, ctx);
    1637          120 :             number->setVisible(t->visible());         //?? override saved property
    1638          120 :             number->setColor(t->color());
    1639          120 :             number->setTrack(t->track());
    1640              :             // move property flags from _number back to tuplet
    1641          720 :             for (auto p : { Pid::FONT_FACE, Pid::FONT_SIZE, Pid::FONT_STYLE, Pid::ALIGN, Pid::POSITION }) {
    1642          600 :                 t->setPropertyFlags(p, number->propertyFlags(p));
    1643              :             }
    1644           67 :         } else if (!readItemProperties(t, e, ctx)) {
    1645            0 :             e.unknown();
    1646              :         }
    1647              :     }
    1648              : 
    1649          120 :     t->setNumber(number);
    1650          120 :     t->setBaseLen(baseLen);
    1651          120 :     t->setRatio(ratio);
    1652              : 
    1653          120 :     Fraction f =  t->baseLen().fraction() * t->ratio().denominator();
    1654          120 :     t->setTicks(f.reduced());
    1655          120 : }
    1656              : 
    1657          491 : void TRead::read(Beam* b, XmlReader& e, ReadContext& ctx)
    1658              : {
    1659         2117 :     while (e.readNextStartElement()) {
    1660         1626 :         const AsciiStringView tag(e.name());
    1661         1626 :         if (tag == "StemDirection") {
    1662          153 :             TRead::readProperty(b, e, ctx, Pid::STEM_DIRECTION);
    1663         1473 :         } else if (TRead::readStyledProperty(b, tag, e, ctx)) {
    1664         1473 :         } else if (tag == "growLeft") {
    1665            0 :             b->setGrowLeft(e.readDouble());
    1666         1473 :         } else if (tag == "growRight") {
    1667            0 :             b->setGrowRight(e.readDouble());
    1668         1473 :         } else if (tag == "Fragment") {
    1669            0 :             BeamFragment* f = new BeamFragment;
    1670            0 :             int idx = b->directionIdx();
    1671            0 :             b->setUserModified(true);
    1672            0 :             double _spatium = b->spatium();
    1673            0 :             while (e.readNextStartElement()) {
    1674            0 :                 const AsciiStringView tag1(e.name());
    1675            0 :                 if (tag1 == "y1") {
    1676            0 :                     f->py1[idx] = e.readDouble() * _spatium;
    1677            0 :                 } else if (tag1 == "y2") {
    1678            0 :                     f->py2[idx] = e.readDouble() * _spatium;
    1679              :                 } else {
    1680            0 :                     e.unknown();
    1681              :                 }
    1682              :             }
    1683            0 :             b->addBeamFragment(f);
    1684         1473 :         } else if (tag == "l1" || tag == "l2") {      // ignore
    1685          982 :             e.skipCurrentElement();
    1686          491 :         } else if (readProperty(b, tag, e, ctx, Pid::BEAM_CROSS_STAFF_MOVE)) {
    1687          491 :         } else if (!readItemProperties(b, e, ctx)) {
    1688            0 :             e.unknown();
    1689              :         }
    1690              :     }
    1691          491 : }
    1692              : 
    1693            0 : void TRead::read(Ambitus* a, XmlReader& e, ReadContext& ctx)
    1694              : {
    1695            0 :     while (e.readNextStartElement()) {
    1696            0 :         if (!readProperties(a, e, ctx)) {
    1697            0 :             e.unknown();
    1698              :         }
    1699              :     }
    1700            0 : }
    1701              : 
    1702            0 : bool TRead::readProperties(Ambitus* a, XmlReader& e, ReadContext& ctx)
    1703              : {
    1704            0 :     const AsciiStringView tag(e.name());
    1705            0 :     if (tag == "head") {
    1706            0 :         TRead::readProperty(a, e, ctx, Pid::HEAD_GROUP);
    1707            0 :     } else if (tag == "headType") {
    1708            0 :         TRead::readProperty(a, e, ctx, Pid::HEAD_TYPE);
    1709            0 :     } else if (tag == "mirror") {
    1710            0 :         TRead::readProperty(a, e, ctx, Pid::MIRROR_HEAD);
    1711            0 :     } else if (tag == "hasLine") {
    1712            0 :         a->setHasLine(e.readInt());
    1713            0 :     } else if (tag == "lineWidth") {
    1714            0 :         TRead::readProperty(a, e, ctx, Pid::LINE_WIDTH);
    1715            0 :     } else if (tag == "topPitch") {
    1716            0 :         a->setTopPitch(e.readInt(), false);
    1717            0 :     } else if (tag == "bottomPitch") {
    1718            0 :         a->setBottomPitch(e.readInt(), false);
    1719            0 :     } else if (tag == "topTpc") {
    1720            0 :         a->setTopTpc(e.readInt(), false);
    1721            0 :     } else if (tag == "bottomTpc") {
    1722            0 :         a->setBottomTpc(e.readInt(), false);
    1723            0 :     } else if (tag == "topAccidental") {
    1724            0 :         while (e.readNextStartElement()) {
    1725            0 :             if (e.name() == "Accidental") {
    1726            0 :                 TRead::read(a->topAccidental(), e, ctx);
    1727              :             } else {
    1728            0 :                 e.skipCurrentElement();
    1729              :             }
    1730              :         }
    1731            0 :     } else if (tag == "bottomAccidental") {
    1732            0 :         while (e.readNextStartElement()) {
    1733            0 :             if (e.name() == "Accidental") {
    1734            0 :                 TRead::read(a->bottomAccidental(), e, ctx);
    1735              :             } else {
    1736            0 :                 e.skipCurrentElement();
    1737              :             }
    1738              :         }
    1739            0 :     } else if (readItemProperties(a, e, ctx)) {
    1740              :     } else {
    1741            0 :         return false;
    1742              :     }
    1743            0 :     return true;
    1744              : }
    1745              : 
    1746            9 : void TRead::read(Accidental* a, XmlReader& e, ReadContext& ctx)
    1747              : {
    1748           27 :     while (e.readNextStartElement()) {
    1749           18 :         const AsciiStringView tag(e.name());
    1750           18 :         if (tag == "bracket") {
    1751            0 :             int i = e.readInt();
    1752            0 :             if (i == 0 || i == 1 || i == 2) {
    1753            0 :                 a->setBracket(AccidentalBracket(i));
    1754              :             }
    1755           18 :         } else if (tag == "subtype") {
    1756            9 :             a->setSubtype(e.readAsciiText());
    1757            9 :         } else if (tag == "role") {
    1758            0 :             a->setRole(TConv::fromXml(e.readAsciiText(), AccidentalRole::AUTO));
    1759            9 :         } else if (tag == "small") {
    1760            0 :             a->setSmall(e.readInt());
    1761            9 :         } else if (readProperty(a, tag, e, ctx, Pid::ACCIDENTAL_STACKING_ORDER_OFFSET)) {
    1762            9 :         } else if (readItemProperties(a, e, ctx)) {
    1763              :         } else {
    1764            0 :             e.unknown();
    1765              :         }
    1766              :     }
    1767            9 : }
    1768              : 
    1769            4 : void TRead::read(Marker* m, XmlReader& e, ReadContext& ctx)
    1770              : {
    1771              :     /// This property was written in the wrong order from 4.6.0-4.6.2
    1772              :     /// It was written before the text style and was reset on initialising the text style
    1773            4 :     std::optional<double> symbolSize;
    1774              : 
    1775           24 :     while (e.readNextStartElement()) {
    1776           20 :         const AsciiStringView tag(e.name());
    1777           20 :         if (tag == "label") {
    1778            4 :             AsciiStringView s(e.readAsciiText());
    1779            4 :             m->setLabel(String::fromAscii(s.ascii()));
    1780           16 :         } else if (readProperty(m, tag, e, ctx, Pid::MARKER_TYPE)) {
    1781           12 :         } else if (readProperty(m, tag, e, ctx, Pid::MARKER_CENTER_ON_SYMBOL)) {
    1782           12 :         } else if (tag == "musicSymbolSize") {
    1783            0 :             symbolSize = e.readDouble();
    1784           12 :         } else if (!readProperties(toTextBase(m), e, ctx)) {
    1785            0 :             e.unknown();
    1786              :         }
    1787              :     }
    1788              : 
    1789            4 :     if (symbolSize.has_value()) {
    1790            0 :         m->setProperty(Pid::MUSIC_SYMBOL_SIZE, symbolSize.value());
    1791            0 :         if (m->isStyled(Pid::MUSIC_SYMBOL_SIZE)) {
    1792            0 :             m->setPropertyFlags(Pid::MUSIC_SYMBOL_SIZE, PropertyFlags::UNSTYLED);
    1793              :         }
    1794              :     }
    1795            4 : }
    1796              : 
    1797            2 : void TRead::read(Jump* j, XmlReader& e, ReadContext& ctx)
    1798              : {
    1799           14 :     while (e.readNextStartElement()) {
    1800           12 :         const AsciiStringView tag(e.name());
    1801           12 :         if (tag == "jumpTo") {
    1802            2 :             j->setJumpTo(e.readText());
    1803           10 :         } else if (tag == "playUntil") {
    1804            2 :             j->setPlayUntil(e.readText());
    1805            8 :         } else if (tag == "continueAt") {
    1806            2 :             j->setContinueAt(e.readText());
    1807            6 :         } else if (tag == "playRepeats") {
    1808            0 :             j->setPlayRepeats(e.readBool());
    1809            6 :         } else if (!readProperties(toTextBase(j), e, ctx)) {
    1810            0 :             e.unknown();
    1811              :         }
    1812              :     }
    1813            2 : }
    1814              : 
    1815            0 : void TRead::read(MeasureNumber* n, XmlReader& xml, ReadContext& ctx)
    1816              : {
    1817            0 :     read(static_cast<MeasureNumberBase*>(n), xml, ctx);
    1818            0 : }
    1819              : 
    1820            0 : void TRead::read(MeasureNumberBase* b, XmlReader& xml, ReadContext& ctx)
    1821              : {
    1822            0 :     while (xml.readNextStartElement()) {
    1823            0 :         if (!readProperties(b, xml, ctx)) {
    1824            0 :             xml.unknown();
    1825              :         }
    1826              :     }
    1827            0 : }
    1828              : 
    1829            0 : bool TRead::readProperties(MeasureNumberBase* n, XmlReader& xml, ReadContext& ctx)
    1830              : {
    1831            0 :     if (TRead::readProperty(n, xml.name(), xml, ctx, Pid::HPLACEMENT)) {
    1832            0 :         return true;
    1833              :     } else {
    1834            0 :         return readProperties(toTextBase(n), xml, ctx);
    1835              :     }
    1836              : }
    1837              : 
    1838            0 : void TRead::read(MMRestRange* r, XmlReader& xml, ReadContext& ctx)
    1839              : {
    1840            0 :     read(static_cast<MeasureNumberBase*>(r), xml, ctx);
    1841            0 : }
    1842              : 
    1843            0 : void TRead::read(SystemDivider* d, XmlReader& e, ReadContext& ctx)
    1844              : {
    1845            0 :     SystemDividerType type = e.attribute("type") == "left" ? SystemDividerType::LEFT : SystemDividerType::RIGHT;
    1846            0 :     d->setDividerType(type);
    1847            0 :     TRead::read(static_cast<Symbol*>(d), e, ctx);
    1848            0 : }
    1849              : 
    1850            0 : void TRead::read(ActionIcon* i, XmlReader& e, ReadContext&)
    1851              : {
    1852            0 :     while (e.readNextStartElement()) {
    1853            0 :         const AsciiStringView tag(e.name());
    1854            0 :         if (tag == "action") {
    1855            0 :             i->setActionType(TConv::fromXml(e.readAsciiText(), ActionIconType::UNDEFINED));
    1856              :         } else {
    1857            0 :             e.unknown();
    1858              :         }
    1859              :     }
    1860            0 : }
    1861              : 
    1862            1 : void TRead::read(Arpeggio* a, XmlReader& e, ReadContext& ctx)
    1863              : {
    1864            3 :     while (e.readNextStartElement()) {
    1865            2 :         const AsciiStringView tag(e.name());
    1866            2 :         if (tag == "subtype") {
    1867            1 :             a->setArpeggioType(TConv::fromXml(e.readAsciiText(), ArpeggioType::NORMAL));
    1868            1 :         } else if (!readProperties(a, e, ctx)) {
    1869            0 :             e.unknown();
    1870              :         }
    1871              :     }
    1872            1 : }
    1873              : 
    1874            1 : bool TRead::readProperties(Arpeggio* a, XmlReader& e, ReadContext& ctx)
    1875              : {
    1876            1 :     const AsciiStringView tag(e.name());
    1877            1 :     if (tag == "userLen1") {
    1878            0 :         a->setUserLen1(e.readDouble() * a->spatium());
    1879            1 :     } else if (tag == "userLen2") {
    1880            0 :         a->setUserLen2(e.readDouble() * a->spatium());
    1881            1 :     } else if (tag == "span") {
    1882            0 :         a->setSpan(e.readInt());
    1883            1 :     } else if (tag == "play") {
    1884            0 :         a->setPlayArpeggio(e.readBool());
    1885            1 :     } else if (tag == "timeStretch") {
    1886            0 :         a->setStretch(e.readDouble());
    1887            1 :     } else if (!readItemProperties(a, e, ctx)) {
    1888            0 :         return false;
    1889              :     }
    1890              : 
    1891            1 :     return true;
    1892              : }
    1893              : 
    1894            0 : void TRead::read(ChordBracket* b, XmlReader& e, ReadContext& ctx)
    1895              : {
    1896            0 :     while (e.readNextStartElement()) {
    1897            0 :         const AsciiStringView tag(e.name());
    1898            0 :         if (readProperty(b, tag, e, ctx, Pid::BRACKET_HOOK_LEN)) {
    1899            0 :         } else if (readProperty(b, tag, e, ctx, Pid::BRACKET_HOOK_POS)) {
    1900            0 :         } else if (readProperty(b, tag, e, ctx, Pid::BRACKET_RIGHT_SIDE)) {
    1901            0 :         } else if (!readProperties(b, e, ctx)) {
    1902            0 :             e.unknown();
    1903              :         }
    1904              :     }
    1905            0 : }
    1906              : 
    1907            4 : void TRead::read(Ornament* o, XmlReader& xml, ReadContext& ctx)
    1908              : {
    1909           21 :     while (xml.readNextStartElement()) {
    1910           13 :         if (!readProperties(o, xml, ctx)) {
    1911            0 :             xml.unknown();
    1912              :         }
    1913              :     }
    1914            4 : }
    1915              : 
    1916           13 : bool TRead::readProperties(Ornament* o, XmlReader& xml, ReadContext& ctx)
    1917              : {
    1918           13 :     const AsciiStringView tag(xml.name());
    1919           13 :     if (readProperty(o, tag, xml, ctx, Pid::INTERVAL_ABOVE)) {
    1920           12 :     } else if (readProperty(o, tag, xml, ctx, Pid::INTERVAL_BELOW)) {
    1921           12 :     } else if (readProperty(o, tag, xml, ctx, Pid::ORNAMENT_SHOW_ACCIDENTAL)) {
    1922           12 :     } else if (readProperty(o, tag, xml, ctx, Pid::ORNAMENT_SHOW_CUE_NOTE)) {
    1923           12 :     } else if (readProperty(o, tag, xml, ctx, Pid::START_ON_UPPER_NOTE)) {
    1924           12 :     } else if (readProperties(toArticulation(o), xml, ctx)) {
    1925            1 :     } else if (tag == "Accidental") {
    1926            0 :         Accidental* accidental = Factory::createAccidental(o);
    1927            0 :         TRead::read(accidental, xml, ctx);
    1928            0 :         accidental->setTrack(ctx.track());
    1929            0 :         accidental->placement() == PlacementV::ABOVE ? o->setAccidentalAbove(accidental) : o->setAccidentalBelow(accidental);
    1930            1 :     } else if (tag == "Chord") {
    1931            1 :         Chord* chord = Factory::createChord(ctx.score()->dummy());
    1932            1 :         TRead::read(chord, xml, ctx);
    1933            1 :         chord->setTrack(ctx.track());
    1934            1 :         chord->setIsTrillCueNote(true);
    1935            1 :         o->setCueNoteChord(chord);
    1936            1 :         o->setNoteAbove(chord->notes().front());
    1937            2 :         for (Note* note : chord->notes()) {
    1938            1 :             compat::CompatUtils::doMigrateNoteParens(note);
    1939              :         }
    1940              :     } else {
    1941            0 :         return false;
    1942              :     }
    1943           13 :     return true;
    1944              : }
    1945              : 
    1946           34 : void TRead::read(Articulation* a, XmlReader& xml, ReadContext& ctx)
    1947              : {
    1948          156 :     while (xml.readNextStartElement()) {
    1949           88 :         if (!readProperties(a, xml, ctx)) {
    1950            0 :             xml.unknown();
    1951              :         }
    1952              :     }
    1953           34 : }
    1954              : 
    1955          100 : bool TRead::readProperties(Articulation* a, XmlReader& xml, ReadContext& ctx)
    1956              : {
    1957          100 :     const AsciiStringView tag(xml.name());
    1958              : 
    1959          100 :     if (tag == "subtype") {
    1960           38 :         AsciiStringView s = xml.readAsciiText();
    1961           38 :         ArticulationTextType textType = TConv::fromXml(s, ArticulationTextType::NO_TEXT);
    1962           38 :         if (textType != ArticulationTextType::NO_TEXT) {
    1963            0 :             a->setTextType(textType);
    1964              :         } else {
    1965           38 :             a->setSymId(SymNames::symIdByName(s));
    1966              :         }
    1967           62 :     } else if (tag == "channel") {
    1968            0 :         a->setChannelName(xml.attribute("name"));
    1969            0 :         xml.readNext();
    1970           62 :     } else if (tag == "anchor") {
    1971            0 :         TRead::readProperty(a, tag, xml, ctx, Pid::ARTICULATION_ANCHOR);
    1972           62 :     } else if (tag == "direction") {
    1973            0 :         TRead::readProperty(a, xml, ctx, Pid::DIRECTION);
    1974           62 :     } else if (tag == "ornamentStyle") {
    1975            0 :         TRead::readProperty(a, xml, ctx, Pid::ORNAMENT_STYLE);
    1976           62 :     } else if (tag == "play") {
    1977            0 :         a->setPlayArticulation(xml.readBool());
    1978           62 :     } else if (tag == "offset") {
    1979            0 :         readItemProperties(a, xml, ctx);
    1980           62 :     } else if (readItemProperties(a, xml, ctx)) {
    1981              :     } else {
    1982            1 :         return false;
    1983              :     }
    1984           99 :     return true;
    1985              : }
    1986              : 
    1987            0 : void TRead::read(Tapping* t, XmlReader& xml, ReadContext& ctx)
    1988              : {
    1989            0 :     while (xml.readNextStartElement()) {
    1990            0 :         AsciiStringView tag = xml.name();
    1991            0 :         if (tag == "hand") {
    1992            0 :             t->setHand(TConv::fromXml(xml.readAsciiText(), TappingHand::INVALID));
    1993            0 :         } else if (tag == TConv::toXml(ElementType::TAPPING_HALF_SLUR)) {
    1994            0 :             TappingHalfSlur* tappingHalfSlur = new TappingHalfSlur(t);
    1995            0 :             read(tappingHalfSlur, xml, ctx);
    1996            0 :             if (tappingHalfSlur->isHalfSlurAbove()) {
    1997            0 :                 t->setHalfSlurAbove(tappingHalfSlur);
    1998              :             } else {
    1999            0 :                 t->setHalfSlurBelow(tappingHalfSlur);
    2000              :             }
    2001            0 :         } else if (!readProperties(toArticulation(t), xml, ctx)) {
    2002            0 :             xml.unknown();
    2003              :         }
    2004              :     }
    2005            0 : }
    2006              : 
    2007            0 : void TRead::read(TappingHalfSlur* t, XmlReader& xml, ReadContext& ctx)
    2008              : {
    2009            0 :     while (xml.readNextStartElement()) {
    2010            0 :         if (xml.name() == "isHalfSlurAbove") {
    2011            0 :             t->setIsHalfSlurAbove(xml.readBool());
    2012            0 :         } else if (!readProperties(toSlur(t), xml, ctx)) {
    2013            0 :             xml.unknown();
    2014              :         }
    2015              :     }
    2016            0 : }
    2017              : 
    2018            0 : void TRead::read(BagpipeEmbellishment* b, XmlReader& e, ReadContext&)
    2019              : {
    2020            0 :     while (e.readNextStartElement()) {
    2021            0 :         const AsciiStringView tag(e.name());
    2022            0 :         if (tag == "subtype") {
    2023            0 :             b->setEmbelType(TConv::fromXml(e.readAsciiText(), EmbellishmentType(0)));
    2024              :         } else {
    2025            0 :             e.unknown();
    2026              :         }
    2027              :     }
    2028            0 : }
    2029              : 
    2030           15 : void TRead::read(BarLine* b, XmlReader& e, ReadContext& ctx)
    2031              : {
    2032              :     // initialize span properties with staff values
    2033           15 :     b->resetProperty(Pid::BARLINE_SPAN);
    2034           15 :     b->resetProperty(Pid::BARLINE_SPAN_FROM);
    2035           15 :     b->resetProperty(Pid::BARLINE_SPAN_TO);
    2036              : 
    2037           47 :     while (e.readNextStartElement()) {
    2038           32 :         const AsciiStringView tag(e.name());
    2039           32 :         if (tag == "subtype") {
    2040            8 :             b->setBarLineType(TConv::fromXml(e.readAsciiText(), BarLineType::NORMAL));
    2041           24 :         } else if (tag == "span") {
    2042            2 :             b->setSpanStaff(e.readBool());
    2043           22 :         } else if (tag == "spanFromOffset") {
    2044            2 :             b->setSpanFrom(e.readInt());
    2045           20 :         } else if (tag == "spanToOffset") {
    2046            1 :             b->setSpanTo(e.readInt());
    2047           19 :         } else if (tag == "Articulation") {
    2048            0 :             Articulation* a = Factory::createArticulation(b->score()->dummy());
    2049            0 :             TRead::read(a, e, ctx);
    2050            0 :             b->add(a);
    2051           19 :         } else if (tag == "Symbol") {
    2052            0 :             Symbol* s = Factory::createSymbol(b);
    2053            0 :             s->setTrack(b->track());
    2054            0 :             TRead::read(s, e, ctx);
    2055            0 :             b->add(s);
    2056           19 :         } else if (tag == "Image") {
    2057            0 :             if (MScore::noImages) {
    2058            0 :                 e.skipCurrentElement();
    2059              :             } else {
    2060            0 :                 Image* image = Factory::createImage(b);
    2061            0 :                 image->setTrack(b->track());
    2062            0 :                 TRead::read(image, e, ctx);
    2063            0 :                 b->add(image);
    2064              :             }
    2065           19 :         } else if (!readItemProperties(b, e, ctx)) {
    2066            0 :             e.unknown();
    2067              :         }
    2068              :     }
    2069           15 : }
    2070              : 
    2071            0 : void TRead::read(Bend* b, XmlReader& e, ReadContext& ctx)
    2072              : {
    2073            0 :     while (e.readNextStartElement()) {
    2074            0 :         const AsciiStringView tag(e.name());
    2075              : 
    2076            0 :         if (TRead::readStyledProperty(b, tag, e, ctx)) {
    2077            0 :         } else if (tag == "point") {
    2078            0 :             PitchValue pv;
    2079            0 :             pv.time    = e.intAttribute("time");
    2080            0 :             pv.pitch   = e.intAttribute("pitch");
    2081            0 :             pv.vibrato = e.intAttribute("vibrato");
    2082            0 :             b->addPoint(pv);
    2083            0 :             e.readNext();
    2084            0 :         } else if (tag == "play") {
    2085            0 :             b->setPlayBend(e.readBool());
    2086            0 :         } else if (!readItemProperties(b, e, ctx)) {
    2087            0 :             e.unknown();
    2088              :         }
    2089              :     }
    2090            0 : }
    2091              : 
    2092          156 : void TRead::read(Box* b, XmlReader& e, ReadContext& ctx)
    2093              : {
    2094         1092 :     while (e.readNextStartElement()) {
    2095          780 :         if (!readProperties(b, e, ctx)) {
    2096            0 :             e.unknown();
    2097              :         }
    2098              :     }
    2099          156 : }
    2100              : 
    2101           13 : void TRead::read(HBox* b, XmlReader& e, ReadContext& ctx)
    2102              : {
    2103           55 :     while (e.readNextStartElement()) {
    2104           29 :         if (!readProperties(b, e, ctx)) {
    2105            0 :             e.unknown();
    2106              :         }
    2107              :     }
    2108           13 : }
    2109              : 
    2110           29 : bool TRead::readProperties(HBox* b, XmlReader& e, ReadContext& ctx)
    2111              : {
    2112           29 :     const AsciiStringView tag(e.name());
    2113           29 :     if (readProperty(b, tag, e, ctx, Pid::CREATE_SYSTEM_HEADER)) {
    2114           29 :     } else if (readProperties(static_cast<Box*>(b), e, ctx)) {
    2115              :     } else {
    2116            0 :         return false;
    2117              :     }
    2118           29 :     return true;
    2119              : }
    2120              : 
    2121          156 : void TRead::read(VBox* b, XmlReader& xml, ReadContext& ctx)
    2122              : {
    2123          156 :     TRead::read(static_cast<Box*>(b), xml, ctx);
    2124          156 : }
    2125              : 
    2126            0 : void TRead::read(FBox* b, XmlReader& xml, ReadContext& ctx)
    2127              : {
    2128            0 :     while (xml.readNextStartElement()) {
    2129            0 :         const AsciiStringView tag(xml.name());
    2130            0 :         if (readProperty(b, tag, xml, ctx, Pid::FRET_FRAME_TEXT_SCALE)) {
    2131            0 :         } else if (readProperty(b, tag, xml, ctx, Pid::FRET_FRAME_DIAGRAM_SCALE)) {
    2132            0 :         } else if (readProperty(b, tag, xml, ctx, Pid::FRET_FRAME_COLUMN_GAP)) {
    2133            0 :         } else if (readProperty(b, tag, xml, ctx, Pid::FRET_FRAME_ROW_GAP)) {
    2134            0 :         } else if (readProperty(b, tag, xml, ctx, Pid::FRET_FRAME_CHORDS_PER_ROW)) {
    2135            0 :         } else if (readProperty(b, tag, xml, ctx, Pid::FRET_FRAME_H_ALIGN)) {
    2136            0 :         } else if (TRead::readProperties(static_cast<Box*>(b), xml, ctx)) {
    2137              :         } else {
    2138            0 :             xml.unknown();
    2139              :         }
    2140              :     }
    2141            0 : }
    2142              : 
    2143            1 : void TRead::read(TBox* b, XmlReader& e, ReadContext& ctx)
    2144              : {
    2145            3 :     while (e.readNextStartElement()) {
    2146            2 :         const AsciiStringView tag(e.name());
    2147            2 :         if (tag == "Text") {
    2148            1 :             TRead::read(b->text(), e, ctx);
    2149            1 :         } else if (TRead::readProperties(static_cast<Box*>(b), e, ctx)) {
    2150              :         } else {
    2151            0 :             e.unknown();
    2152              :         }
    2153              :     }
    2154            1 : }
    2155              : 
    2156            0 : bool TRead::readBoxProperties(Box* b, XmlReader& e, ReadContext& ctx)
    2157              : {
    2158            0 :     if (b->isHBox()) {
    2159            0 :         return readProperties(dynamic_cast<HBox*>(b), e, ctx);
    2160              :     }
    2161            0 :     return readProperties(b, e, ctx);
    2162              : }
    2163              : 
    2164          810 : bool TRead::readProperties(Box* b, XmlReader& e, ReadContext& ctx)
    2165              : {
    2166          810 :     const AsciiStringView tag(e.name());
    2167          810 :     if (tag == "height") {
    2168          156 :         b->setBoxHeight(Spatium(e.readDouble()));
    2169          654 :     } else if (tag == "width") {
    2170           13 :         b->setBoxWidth(Spatium(e.readDouble()));
    2171          641 :     } else if (tag == "topGap") {
    2172            0 :         b->setTopGap(Spatium(e.readDouble()));
    2173            0 :         b->setPropertyFlags(Pid::TOP_GAP, PropertyFlags::UNSTYLED);
    2174          641 :     } else if (tag == "bottomGap") {
    2175            0 :         b->setBottomGap(Spatium(e.readDouble()));
    2176            0 :         b->setPropertyFlags(Pid::BOTTOM_GAP, PropertyFlags::UNSTYLED);
    2177          641 :     } else if (tag == "leftMargin") {
    2178            0 :         b->setLeftMargin(e.readDouble());
    2179          641 :     } else if (tag == "rightMargin") {
    2180            0 :         b->setRightMargin(e.readDouble());
    2181          641 :     } else if (tag == "topMargin") {
    2182            0 :         b->setTopMargin(e.readDouble());
    2183          641 :     } else if (tag == "bottomMargin") {
    2184            0 :         b->setBottomMargin(e.readDouble());
    2185          641 :     } else if (tag == "boxAutoSize") {
    2186           11 :         b->setAutoSizeEnabled(e.readBool());
    2187          630 :     } else if (tag == "Text") {
    2188              :         Text* t;
    2189          263 :         if (b->isTBox()) {
    2190            0 :             t = toTBox(b)->text();
    2191            0 :             TRead::read(t, e, ctx);
    2192              :         } else {
    2193          263 :             t = Factory::createText(b);
    2194          263 :             TRead::read(t, e, ctx);
    2195          263 :             if (t->empty()) {
    2196            0 :                 LOGD("read empty text");
    2197              :             } else {
    2198          263 :                 b->add(t);
    2199              :             }
    2200              :         }
    2201          367 :     } else if (tag == "Symbol") {
    2202            0 :         Symbol* s = new Symbol(b);
    2203            0 :         TRead::read(s, e, ctx);
    2204            0 :         b->add(s);
    2205          367 :     } else if (tag == "Image") {
    2206            0 :         if (MScore::noImages) {
    2207            0 :             e.skipCurrentElement();
    2208              :         } else {
    2209            0 :             Image* image = new Image(b);
    2210            0 :             image->setTrack(ctx.track());
    2211            0 :             TRead::read(image, e, ctx);
    2212            0 :             b->add(image);
    2213              :         }
    2214          367 :     } else if (tag == "FretDiagram") {
    2215            0 :         FretDiagram* f = Factory::createFretDiagram(b->score()->dummy());
    2216            0 :         TRead::read(f, e, ctx);
    2217              :         //! TODO Looks like a bug.
    2218              :         //! The FretDiagram parent must be Segment
    2219              :         //! there is a method: `Segment* segment() const { return toSegment(parent()); }`,
    2220              :         //! but when we add it to Box, the parent will be rewritten.
    2221            0 :         b->add(f);
    2222          367 :     } else if (tag == "HBox") {
    2223              :         // m_parent is used here (rather than system()) because explicit parent isn't set for this object
    2224              :         // until it is fully read. m_parent is nonetheless valid and using it here matches MU3 behavior.
    2225              :         // If we do not set the parent of this new box correctly, it will cause a crash on read()
    2226              :         // because it needs access to the system it is being added to. (c.r. issue #14643)
    2227            0 :         if (b->parent() && b->parent()->isSystem()) {
    2228            0 :             HBox* hb = new HBox(b->score());
    2229            0 :             TRead::read(hb, e, ctx);
    2230              :             //! TODO Looks like a bug.
    2231              :             //! The HBox parent must be System
    2232              :             //! there is a method: `System* system() const { return (System*)parent(); }`,
    2233              :             //! but when we add it to Box, the parent will be rewritten.
    2234            0 :             b->add(hb);
    2235              :         }
    2236          367 :     } else if (tag == "VBox") {
    2237            0 :         if (b->parent() && b->parent()->isSystem()) {
    2238            0 :             VBox* vb = new VBox(b->score());
    2239            0 :             TRead::read(vb, e, ctx);
    2240              :             //! TODO Looks like a bug.
    2241              :             //! The VBox parent must be System
    2242              :             //! there is a method: `System* system() const { return (System*)parent(); }`,
    2243              :             //! but when we add it to Box, the parent will be rewritten.
    2244            0 :             b->add(vb);
    2245              :         }
    2246          367 :     } else if (TRead::readProperty(b, tag, e, ctx, Pid::PADDING_TO_NOTATION_ABOVE)) {
    2247          366 :     } else if (TRead::readProperty(b, tag, e, ctx, Pid::PADDING_TO_NOTATION_BELOW)) {
    2248          365 :     } else if (TRead::readProperties(static_cast<MeasureBase*>(b), e, ctx)) {
    2249              :     } else {
    2250            0 :         return false;
    2251              :     }
    2252          810 :     return true;
    2253              : }
    2254              : 
    2255         4800 : bool TRead::readProperties(MeasureBase* b, XmlReader& e, ReadContext& ctx)
    2256              : {
    2257         4800 :     const AsciiStringView tag(e.name());
    2258         4800 :     if (tag == "LayoutBreak") {
    2259          103 :         LayoutBreak* lb = Factory::createLayoutBreak(b);
    2260          103 :         TRead::read(lb, e, ctx);
    2261          103 :         lb->setTrack(0);
    2262          103 :         bool doAdd = true;
    2263          103 :         switch (lb->layoutBreakType()) {
    2264           79 :         case LayoutBreakType::LINE:
    2265           79 :             if (b->lineBreak()) {
    2266            0 :                 doAdd = false;
    2267              :             }
    2268           79 :             break;
    2269            0 :         case LayoutBreakType::PAGE:
    2270            0 :             if (b->pageBreak()) {
    2271            0 :                 doAdd = false;
    2272              :             }
    2273            0 :             break;
    2274            0 :         case LayoutBreakType::SECTION:
    2275            0 :             if (b->sectionBreak()) {
    2276            0 :                 doAdd = false;
    2277              :             }
    2278            0 :             break;
    2279           24 :         case LayoutBreakType::NOBREAK:
    2280           24 :             if (b->noBreak()) {
    2281            0 :                 doAdd = false;
    2282              :             }
    2283           24 :             break;
    2284              :         }
    2285          103 :         if (doAdd) {
    2286          103 :             b->add(lb);
    2287          103 :             b->cleanupLayoutBreaks(false);
    2288              :         }
    2289         4697 :     } else if (tag == "StaffTypeChange") {
    2290            0 :         StaffTypeChange* stc = Factory::createStaffTypeChange(b);
    2291            0 :         stc->setTrack(ctx.track());
    2292            0 :         TRead::read(stc, e, ctx);
    2293            0 :         b->add(stc);
    2294         4697 :     } else if (readItemProperties(b, e, ctx)) {
    2295              :     } else {
    2296            0 :         return false;
    2297              :     }
    2298         4800 :     return true;
    2299              : }
    2300              : 
    2301            0 : void TRead::read(Bracket* b, XmlReader& e, ReadContext& ctx)
    2302              : {
    2303            0 :     BracketItem* bi = Factory::createBracketItem(b->score()->dummy());
    2304            0 :     bi->setBracketType(TConv::fromXml(e.asciiAttribute("type"), BracketType::NORMAL));
    2305              : 
    2306            0 :     while (e.readNextStartElement()) {
    2307            0 :         if (e.name() == "level") {
    2308            0 :             bi->setColumn(e.readInt());
    2309            0 :         } else if (!readItemProperties(b, e, ctx)) {
    2310            0 :             e.unknown();
    2311              :         }
    2312              :     }
    2313              : 
    2314            0 :     b->setBracketItem(bi);
    2315            0 : }
    2316              : 
    2317           11 : void TRead::read(Breath* b, XmlReader& e, ReadContext& ctx)
    2318              : {
    2319           37 :     while (e.readNextStartElement()) {
    2320           26 :         const AsciiStringView tag(e.name());
    2321           26 :         if (tag == "symbol") {
    2322           11 :             b->setSymId(SymNames::symIdByName(e.readAsciiText()));
    2323           15 :         } else if (tag == "pause") {
    2324            1 :             b->setPause(e.readDouble());
    2325           14 :         } else if (!readItemProperties(b, e, ctx)) {
    2326            0 :             e.unknown();
    2327              :         }
    2328              :     }
    2329           11 : }
    2330              : 
    2331           10 : bool TRead::readProperties(BSymbol* sym, XmlReader& e, ReadContext& ctx)
    2332              : {
    2333           10 :     const AsciiStringView tag = e.name();
    2334              : 
    2335           10 :     if (readItemProperties(sym, e, ctx)) {
    2336           10 :         return true;
    2337            0 :     } else if (tag == "systemFlag") {
    2338            0 :         sym->setSystemFlag(e.readInt());
    2339            0 :     } else if (tag == "Symbol") {
    2340            0 :         Symbol* s = Factory::createSymbol(sym);
    2341            0 :         TRead::read(s, e, ctx);
    2342            0 :         sym->add(s);
    2343            0 :     } else if (tag == "FSymbol") {
    2344            0 :         FSymbol* s = Factory::createFSymbol(sym);
    2345            0 :         TRead::read(s, e, ctx);
    2346            0 :         sym->add(s);
    2347            0 :     } else if (tag == "Image") {
    2348            0 :         if (MScore::noImages) {
    2349            0 :             e.skipCurrentElement();
    2350              :         } else {
    2351            0 :             Image* image = new Image(sym);
    2352            0 :             TRead::read(image, e, ctx);
    2353            0 :             sym->add(image);
    2354              :         }
    2355              :     } else {
    2356            0 :         return false;
    2357              :     }
    2358            0 :     return true;
    2359              : }
    2360              : 
    2361            7 : void TRead::read(Symbol* sym, XmlReader& e, ReadContext& ctx)
    2362              : {
    2363            7 :     SymId symId = SymId::noSym;
    2364            7 :     String fontName;
    2365           24 :     while (e.readNextStartElement()) {
    2366           17 :         const AsciiStringView tag(e.name());
    2367           17 :         if (tag == "name") {
    2368            7 :             String val(e.readText());
    2369            7 :             symId = SymNames::symIdByName(val);
    2370            7 :             if (val != "noSym" && symId == SymId::noSym) {
    2371              :                 // if symbol name not found, fall back to user names
    2372              :                 // TODO: does it make sense? user names are probably localized
    2373            0 :                 symId = SymNames::symIdByUserName(val);
    2374            0 :                 if (symId == SymId::noSym) {
    2375            0 :                     LOGD("unknown symbol <%s>, falling back to no symbol", muPrintable(val));
    2376              :                     // set a default symbol, or layout() will crash
    2377            0 :                     symId = SymId::noSym;
    2378              :                 }
    2379              :             }
    2380            7 :             sym->setSym(symId);
    2381           17 :         } else if (tag == "font") {
    2382            0 :             readProperty(sym, e, ctx, Pid::SCORE_FONT);
    2383           10 :         } else if (readProperty(sym, tag, e, ctx, Pid::SCORE_FONT)) {
    2384           10 :         } else if (readProperty(sym, tag, e, ctx, Pid::SYMBOLS_SIZE)) {
    2385           10 :         } else if (readProperty(sym, tag, e, ctx, Pid::SYMBOL_ANGLE)) {
    2386           10 :         } else if (tag == "Symbol") {
    2387            0 :             Symbol* s = new Symbol(sym);
    2388            0 :             TRead::read(s, e, ctx);
    2389            0 :             sym->add(s);
    2390           10 :         } else if (tag == "Image") {
    2391            0 :             if (MScore::noImages) {
    2392            0 :                 e.skipCurrentElement();
    2393              :             } else {
    2394            0 :                 Image* image = new Image(sym);
    2395            0 :                 TRead::read(image, e, ctx);
    2396            0 :                 sym->add(image);
    2397              :             }
    2398           10 :         } else if (!TRead::readProperties(static_cast<BSymbol*>(sym), e, ctx)) {
    2399            0 :             e.unknown();
    2400              :         }
    2401              :     }
    2402              : 
    2403            7 :     sym->setPos(PointF());
    2404            7 : }
    2405              : 
    2406            0 : void TRead::read(SoundFlag* item, XmlReader& xml, ReadContext&)
    2407              : {
    2408            0 :     while (xml.readNextStartElement()) {
    2409            0 :         const AsciiStringView tag(xml.name());
    2410              : 
    2411            0 :         if (tag == "play") {
    2412            0 :             item->setPlay(xml.readBool());
    2413            0 :         } else if (tag == "presets") {
    2414            0 :             item->setSoundPresets(xml.readText().split(u","));
    2415            0 :         } else if (tag == "playingTechnique") {
    2416            0 :             item->setPlayingTechnique(xml.readText());
    2417            0 :         } else if (tag == "applyToAllStaves") {
    2418            0 :             item->setApplyToAllStaves(xml.readBool());
    2419              :         } else {
    2420            0 :             xml.unknown();
    2421              :         }
    2422              :     }
    2423            0 : }
    2424              : 
    2425            0 : void TRead::read(FSymbol* sym, XmlReader& e, ReadContext& ctx)
    2426              : {
    2427            0 :     Font font = sym->font();
    2428            0 :     while (e.readNextStartElement()) {
    2429            0 :         const AsciiStringView tag(e.name());
    2430            0 :         if (tag == "font") {
    2431            0 :             font.setFamily(e.readText(), Font::Type::Unknown);
    2432            0 :         } else if (tag == "fontsize") {
    2433            0 :             font.setPointSizeF(e.readDouble());
    2434            0 :         } else if (tag == "code") {
    2435            0 :             sym->setCode(e.readInt());
    2436            0 :         } else if (!TRead::readProperties(static_cast<BSymbol*>(sym), e, ctx)) {
    2437            0 :             e.unknown();
    2438              :         }
    2439              :     }
    2440              : 
    2441            0 :     sym->setPos(PointF());
    2442            0 :     sym->setFont(font);
    2443            0 : }
    2444              : 
    2445         3044 : void TRead::read(Chord* ch, XmlReader& e, ReadContext& ctx)
    2446              : {
    2447        15186 :     while (e.readNextStartElement()) {
    2448         9098 :         if (TRead::readProperties(ch, e, ctx)) {
    2449              :         } else {
    2450            0 :             e.unknown();
    2451              :         }
    2452              :     }
    2453         3044 : }
    2454              : 
    2455         9098 : bool TRead::readProperties(Chord* ch, XmlReader& e, ReadContext& ctx)
    2456              : {
    2457         9098 :     const AsciiStringView tag(e.name());
    2458              : 
    2459         9098 :     if (tag == "Note") {
    2460         3334 :         Note* note = Factory::createNote(ch);
    2461              :         // the note needs to know the properties of the track it belongs to
    2462         3334 :         note->setTrack(ch->track());
    2463         3334 :         TRead::read(note, e, ctx);
    2464         3334 :         ch->add(note);
    2465         5764 :     } else if (TRead::readProperties(toChordRest(ch), e, ctx)) {
    2466           45 :     } else if (tag == "Stem") {
    2467            0 :         Stem* s = Factory::createStem(ch);
    2468            0 :         TRead::read(s, e, ctx);
    2469            0 :         ch->add(s);
    2470           45 :     } else if (tag == "Hook") {
    2471            0 :         Hook* hook = new Hook(ch);
    2472            0 :         TRead::read(hook, e, ctx);
    2473            0 :         ch->setHook(hook);
    2474            0 :         ch->add(hook);
    2475           45 :     } else if (tag == "appoggiatura") {
    2476            3 :         ch->setNoteType(NoteType::APPOGGIATURA);
    2477            3 :         e.readNext();
    2478           42 :     } else if (tag == "acciaccatura") {
    2479            4 :         ch->setNoteType(NoteType::ACCIACCATURA);
    2480            4 :         e.readNext();
    2481           38 :     } else if (tag == "grace4") {
    2482            0 :         ch->setNoteType(NoteType::GRACE4);
    2483            0 :         e.readNext();
    2484           38 :     } else if (tag == "grace16") {
    2485            0 :         ch->setNoteType(NoteType::GRACE16);
    2486            0 :         e.readNext();
    2487           38 :     } else if (tag == "grace32") {
    2488            1 :         ch->setNoteType(NoteType::GRACE32);
    2489            1 :         e.readNext();
    2490           37 :     } else if (tag == "grace8after") {
    2491            0 :         ch->setNoteType(NoteType::GRACE8_AFTER);
    2492            0 :         e.readNext();
    2493           37 :     } else if (tag == "grace16after") {
    2494            0 :         ch->setNoteType(NoteType::GRACE16_AFTER);
    2495            0 :         e.readNext();
    2496           37 :     } else if (tag == "grace32after") {
    2497            0 :         ch->setNoteType(NoteType::GRACE32_AFTER);
    2498            0 :         e.readNext();
    2499           37 :     } else if (tag == "StemSlash") {
    2500            0 :         StemSlash* ss = Factory::createStemSlash(ch);
    2501            0 :         TRead::read(ss, e, ctx);
    2502            0 :         ch->add(ss);
    2503           37 :     } else if (TRead::readProperty(ch, tag, e, ctx, Pid::STEM_DIRECTION)) {
    2504           19 :     } else if (tag == "noStem") {
    2505            2 :         ch->setNoStem(e.readInt());
    2506           17 :     } else if (tag == "showStemSlash") {
    2507            0 :         ch->setShowStemSlash(e.readBool());
    2508           17 :     } else if (tag == "Arpeggio") {
    2509            1 :         Arpeggio* arpeggio = Factory::createArpeggio(ch);
    2510            1 :         arpeggio->setTrack(ch->track());
    2511            1 :         TRead::read(arpeggio, e, ctx);
    2512            1 :         ch->setArpeggio(arpeggio);
    2513           16 :     } else if (tag == "ChordBracket") {
    2514            0 :         ChordBracket* bracket = Factory::createChordBracket(ch);
    2515            0 :         bracket->setTrack(ch->track());
    2516            0 :         TRead::read(bracket, e, ctx);
    2517            0 :         ch->add(bracket);
    2518           16 :     } else if (tag == "Tremolo") { // compat
    2519            0 :         compat::TremoloCompat tcompat { ch };
    2520            0 :         TRead::read(&tcompat, e, ctx);
    2521            0 :         if (tcompat.two) {
    2522            0 :             tcompat.two->setOwnershipParent(ch);
    2523            0 :             tcompat.two->setDurationType(ch->durationType());
    2524            0 :             ch->setTremoloTwoChord(tcompat.two, false);
    2525            0 :         } else if (tcompat.single) {
    2526            0 :             tcompat.single->setOwnershipParent(ch);
    2527            0 :             tcompat.single->setDurationType(ch->durationType());
    2528            0 :             ch->setTremoloSingleChord(tcompat.single);
    2529              :         } else {
    2530            0 :             UNREACHABLE;
    2531              :         }
    2532           16 :     } else if (tag == "TremoloSingleChord") {
    2533            1 :         TremoloSingleChord* trem = Factory::createTremoloSingleChord(ch);
    2534            1 :         trem->setTrack(ch->track());
    2535            1 :         TRead::read(trem, e, ctx);
    2536            1 :         trem->setDurationType(ch->durationType());
    2537            1 :         ch->setTremoloSingleChord(trem);
    2538           15 :     } else if (tag == "TremoloTwoChord") {
    2539            3 :         TremoloTwoChord* trem = Factory::createTremoloTwoChord(ch);
    2540            3 :         trem->setTrack(ch->track());
    2541            3 :         TRead::read(trem, e, ctx);
    2542            3 :         trem->setDurationType(ch->durationType());
    2543            3 :         ch->setTremoloTwoChord(trem, false);
    2544           12 :     } else if (tag == "ChordLine") {
    2545            9 :         ChordLine* cl = Factory::createChordLine(ch);
    2546            9 :         TRead::read(cl, e, ctx);
    2547            9 :         ch->add(cl);
    2548            3 :     } else if (tag == "combineVoice") {
    2549            0 :         readProperty(ch, tag, e, ctx, Pid::COMBINE_VOICE);
    2550            3 :     } else if (tag == "NoteParenGroup") {
    2551            3 :         readNoteParenGroup(ch, e, ctx);
    2552              :     } else {
    2553            0 :         return false;
    2554              :     }
    2555              : 
    2556         9098 :     if (!ch->visible()) {
    2557              :         // By convention, the chord can't be set to invisible (only its elements can).
    2558              :         // If it was written and read as invisible that was an error so we fix it here.
    2559            0 :         ch->setVisible(true);
    2560              :     }
    2561              : 
    2562         9098 :     return true;
    2563              : }
    2564              : 
    2565        26447 : bool TRead::readProperties(ChordRest* ch, XmlReader& e, ReadContext& ctx)
    2566              : {
    2567        26447 :     const AsciiStringView tag(e.name());
    2568              : 
    2569        26447 :     if (tag == "durationType") {
    2570         9524 :         ch->setDurationType(TConv::fromXml(e.readAsciiText(), DurationType::V_QUARTER));
    2571         9524 :         if (ch->actualDurationType().type() != DurationType::V_MEASURE) {
    2572         3731 :             ch->setTicks(ch->actualDurationType().fraction());
    2573              :         }
    2574        16923 :     } else if (tag == "BeamMode") {
    2575          167 :         ch->setBeamMode(TConv::fromXml(e.readAsciiText(), BeamMode::AUTO));
    2576        16756 :     } else if (tag == "Articulation") {
    2577           12 :         Articulation* atr = Factory::createArticulation(ch);
    2578           12 :         atr->setTrack(ch->track());
    2579           12 :         TRead::read(atr, e, ctx);
    2580           12 :         ch->add(atr);
    2581        16744 :     } else if (tag == "Ornament") {
    2582            0 :         Ornament* ornament = Factory::createOrnament(ch);
    2583            0 :         ornament->setTrack(ch->track());
    2584            0 :         TRead::read(ornament, e, ctx);
    2585            0 :         ch->add(ornament);
    2586        16744 :     } else if (tag == "Tapping") {
    2587            0 :         Tapping* tapping = Factory::createTapping(ch);
    2588            0 :         tapping->setTrack(ch->track());
    2589            0 :         TRead::read(tapping, e, ctx);
    2590            0 :         ch->add(tapping);
    2591        16744 :     } else if (tag == "small") {
    2592            1 :         ch->setSmall(e.readInt());
    2593        16743 :     } else if (tag == "duration") {
    2594         5799 :         ch->setTicks(e.readFraction());
    2595        10944 :     } else if (tag == "dots") {
    2596            6 :         ch->setDots(e.readInt());
    2597        10938 :     } else if (tag == "staffMove") {
    2598            1 :         ch->setStaffMove(e.readInt());
    2599            1 :         ch->checkStaffMoveValidity();
    2600        10937 :     } else if (tag == "Lyrics") {
    2601            9 :         Lyrics* lyr = Factory::createLyrics(ch);
    2602            9 :         lyr->setTrack(ctx.track());
    2603            9 :         TRead::read(lyr, e, ctx);
    2604            9 :         ch->add(lyr);
    2605        10928 :     } else if (tag == "pos") {
    2606            0 :         PointF pt = e.readPoint();
    2607            0 :         ch->setOffset(pt * ch->spatium());
    2608        10928 :     } else if (!readItemProperties(ch, e, ctx)) {
    2609           45 :         return false;
    2610              :     }
    2611        26402 :     return true;
    2612              : }
    2613              : 
    2614           11 : void TRead::read(ChordLine* l, XmlReader& e, ReadContext& ctx)
    2615              : {
    2616           38 :     while (e.readNextStartElement()) {
    2617           27 :         const AsciiStringView tag(e.name());
    2618           27 :         if (tag == "Path") {
    2619            0 :             compat::CompatUtils::readChordLinePath(l, e);
    2620           27 :         } else if (tag == "subtype") {
    2621           11 :             l->setChordLineType(TConv::fromXml(e.readAsciiText(), ChordLineType::NOTYPE));
    2622           16 :         } else if (tag == "straight") {
    2623            0 :             l->setStraight(e.readInt());
    2624           16 :         } else if (tag == "wavy") {
    2625            0 :             l->setWavy(e.readInt());
    2626           16 :         } else if (tag == "lengthX" || tag == "lengthY") { // obsolete
    2627            0 :             e.skipCurrentElement();
    2628           16 :         } else if (readProperty(l, tag, e, ctx, Pid::BEZIER_OFFSET1)) {
    2629           16 :         } else if (readProperty(l, tag, e, ctx, Pid::BEZIER_OFFSET2)) {
    2630           15 :         } else if (readProperty(l, tag, e, ctx, Pid::BEZIER_OFFSET3)) {
    2631           15 :         } else if (readProperty(l, tag, e, ctx, Pid::BEZIER_OFFSET4)) {
    2632           14 :         } else if (tag == "play") {
    2633            0 :             l->setPlayChordLine(e.readBool());
    2634           14 :         } else if (!readItemProperties(l, e, ctx)) {
    2635            0 :             e.unknown();
    2636              :         }
    2637              :     }
    2638           11 : }
    2639              : 
    2640          172 : void TRead::read(Clef* c, XmlReader& e, ReadContext& ctx, bool* isHeader)
    2641              : {
    2642          922 :     while (e.readNextStartElement()) {
    2643          750 :         const AsciiStringView tag(e.name());
    2644          750 :         if (tag == "concertClefType") {
    2645          172 :             c->setConcertClef(TConv::fromXml(e.readAsciiText(), ClefType::G));
    2646          578 :         } else if (tag == "transposingClefType") {
    2647          172 :             c->setTransposingClef(TConv::fromXml(e.readAsciiText(), ClefType::G));
    2648          406 :         } else if (tag == "showCourtesyClef") {
    2649            0 :             c->setShowCourtesy(e.readInt());
    2650          406 :         } else if (tag == "forInstrumentChange") {
    2651            0 :             c->setForInstrumentChange(e.readBool());
    2652          406 :         } else if (tag == "clefToBarlinePos") {
    2653            0 :             c->setClefToBarlinePosition(ClefToBarlinePosition(e.readInt()));
    2654          406 :         } else if (tag == "isHeader") {
    2655          168 :             const bool header = e.readBool();
    2656          168 :             if (isHeader) {
    2657          168 :                 *isHeader = header;
    2658              :             }
    2659          238 :         } else if (!readItemProperties(c, e, ctx)) {
    2660            0 :             e.unknown();
    2661              :         }
    2662              :     }
    2663              : 
    2664          172 :     if (c->clefType() == ClefType::INVALID) {
    2665            0 :         c->setClefType(ClefType::G);
    2666              :     }
    2667          172 : }
    2668              : 
    2669            0 : void TRead::read(Capo* c, XmlReader& xml, ReadContext& ctx)
    2670              : {
    2671            0 :     CapoParams params = c->params();
    2672              : 
    2673            0 :     while (xml.readNextStartElement()) {
    2674            0 :         const AsciiStringView tag(xml.name());
    2675              : 
    2676            0 :         if (tag == "active") {
    2677            0 :             params.active = xml.readBool();
    2678            0 :         } else if (tag == "fretPosition") {
    2679            0 :             params.fretPosition = xml.readInt();
    2680            0 :         } else if (tag == "string") {
    2681            0 :             string_idx_t idx = static_cast<string_idx_t>(xml.intAttribute("no"));
    2682              : 
    2683            0 :             while (xml.readNextStartElement()) {
    2684            0 :                 const AsciiStringView stringTag(xml.name());
    2685              : 
    2686            0 :                 if (stringTag == "apply") {
    2687            0 :                     bool apply = xml.readBool();
    2688            0 :                     if (!apply) {
    2689            0 :                         params.ignoredStrings.insert(idx);
    2690              :                     }
    2691              :                 } else {
    2692            0 :                     xml.unknown();
    2693              :                 }
    2694              :             }
    2695            0 :         } else if (tag == "generateText") {
    2696            0 :             c->setProperty(Pid::CAPO_GENERATE_TEXT, xml.readBool());
    2697            0 :         } else if (TRead::readProperty(c, tag, xml, ctx, Pid::CAPO_TRANSPOSE_MODE)) {
    2698            0 :             continue;
    2699            0 :         } else if (!readProperties(static_cast<StaffTextBase*>(c), xml, ctx)) {
    2700            0 :             xml.unknown();
    2701              :         }
    2702              :     }
    2703            0 :     params.transposeMode = c->params().transposeMode;
    2704              : 
    2705            0 :     c->setParams(params);
    2706            0 : }
    2707              : 
    2708            0 : bool TRead::readProperties(Clef* c, XmlReader& xml, ReadContext& ctx)
    2709              : {
    2710            0 :     return readItemProperties(c, xml, ctx);
    2711              : }
    2712              : 
    2713           10 : void TRead::read(Fingering* f, XmlReader& e, ReadContext& ctx)
    2714              : {
    2715           53 :     while (e.readNextStartElement()) {
    2716           33 :         if (!readProperties(toTextBase(f), e, ctx)) {
    2717            0 :             e.unknown();
    2718              :         }
    2719              :     }
    2720           10 : }
    2721              : 
    2722            4 : void TRead::read(Glissando* g, XmlReader& e, ReadContext& ctx)
    2723              : {
    2724            4 :     g->eraseSpannerSegments();
    2725              : 
    2726            4 :     staff_idx_t staffIdx = track2staff(ctx.track());
    2727            4 :     Staff* staff = ctx.score()->staff(staffIdx);
    2728            4 :     if (staff) {
    2729            4 :         String instrId = staff->part()->instrumentId(g->tick());
    2730            4 :         g->setIsHarpGliss(instrId == "harp");
    2731            4 :     }
    2732            4 :     g->resetProperty(Pid::GLISS_STYLE);
    2733              : 
    2734           25 :     while (e.readNextStartElement()) {
    2735           21 :         const AsciiStringView tag = e.name();
    2736           21 :         if (tag == "text") {
    2737            0 :             TRead::readProperty(g, e, ctx, Pid::GLISS_TEXT);
    2738           21 :         } else if (tag == "isHarpGliss" && ctx.pasteMode()) {
    2739            1 :             g->setIsHarpGliss(e.readBool());
    2740            1 :             g->resetProperty(Pid::GLISS_STYLE);
    2741           20 :         } else if (tag == "easeInSpin") {
    2742            0 :             g->setEaseIn(e.readInt());
    2743           20 :         } else if (tag == "easeOutSpin") {
    2744            0 :             g->setEaseOut(e.readInt());
    2745           20 :         } else if (tag == "glissandoShift") {
    2746            0 :             g->setGlissandoShift(e.readBool());
    2747           20 :         } else if (!TRead::readProperties(static_cast<SLine*>(g), e, ctx)) {
    2748            0 :             e.unknown();
    2749              :         }
    2750              :     }
    2751            4 : }
    2752              : 
    2753           41 : void TRead::read(GradualTempoChange* c, XmlReader& xml, ReadContext& ctx)
    2754              : {
    2755          416 :     while (xml.readNextStartElement()) {
    2756          375 :         const AsciiStringView tag(xml.name());
    2757              : 
    2758          375 :         if (TRead::readProperty(c, tag, xml, ctx, Pid::TEMPO_CHANGE_TYPE)) {
    2759            3 :             continue;
    2760              :         }
    2761              : 
    2762          373 :         if (TRead::readProperty(c, tag, xml, ctx, Pid::TEMPO_EASING_METHOD)) {
    2763            0 :             continue;
    2764              :         }
    2765              : 
    2766          373 :         if (TRead::readProperty(c, tag, xml, ctx, Pid::TEMPO_CHANGE_FACTOR)) {
    2767            1 :             continue;
    2768              :         }
    2769              : 
    2770          372 :         if (TRead::readProperty(c, tag, xml, ctx, Pid::SNAP_AFTER)) {
    2771            0 :             continue;
    2772              :         }
    2773              : 
    2774          372 :         if (!readProperties(toTextLineBase(c), xml, ctx)) {
    2775            0 :             xml.unknown();
    2776              :         }
    2777              :     }
    2778           41 :     if (ctx.mscVersion() < 470) {
    2779            0 :         compat::CompatUtils::setTextLineTextPositionFromAlign(c);
    2780              :     }
    2781           41 : }
    2782              : 
    2783            0 : void TRead::read(Groups* g, XmlReader& e, ReadContext&)
    2784              : {
    2785            0 :     while (e.readNextStartElement()) {
    2786            0 :         const AsciiStringView tag(e.name());
    2787            0 :         if (tag == "Node") {
    2788            0 :             GroupNode n;
    2789            0 :             n.pos    = e.intAttribute("pos");
    2790            0 :             n.action = e.intAttribute("action");
    2791            0 :             g->addNode(n);
    2792            0 :             e.skipCurrentElement();
    2793              :         } else {
    2794            0 :             e.unknown();
    2795              :         }
    2796              :     }
    2797            0 : }
    2798              : 
    2799            4 : void TRead::read(GuitarBend* g, XmlReader& e, ReadContext& ctx)
    2800              : {
    2801            4 :     g->eraseSpannerSegments();
    2802              : 
    2803           32 :     while (e.readNextStartElement()) {
    2804           28 :         const AsciiStringView tag = e.name();
    2805           28 :         if (tag == "guitarBendType") {
    2806            4 :             g->setBendType(TConv::fromXml(e.readAsciiText(), GuitarBendType::BEND));
    2807           24 :         } else if (tag == "GuitarBendHold") {
    2808            0 :             GuitarBendHold* hold = new GuitarBendHold(g);
    2809            0 :             TRead::read(hold, e, ctx);
    2810            0 :             g->setHoldLine(hold);
    2811           24 :         } else if (TRead::readProperty(g, tag, e, ctx, Pid::DIRECTION)) {
    2812           24 :         } else if (TRead::readProperty(g, tag, e, ctx, Pid::BEND_SHOW_HOLD_LINE)) {
    2813           24 :         } else if (TRead::readProperty(g, tag, e, ctx, Pid::BEND_START_TIME_FACTOR)) {
    2814           20 :         } else if (TRead::readProperty(g, tag, e, ctx, Pid::BEND_TARGET_TIME_FACTOR)) {
    2815           20 :         } else if (TRead::readProperty(g, tag, e, ctx, Pid::BEND_END_TIME_FACTOR)) {
    2816           16 :         } else if (TRead::readProperty(g, tag, e, ctx, Pid::GUITAR_DIVE_TAB_POS)) {
    2817           16 :         } else if (TRead::readProperty(g, tag, e, ctx, Pid::GUITAR_BEND_AMOUNT)) {
    2818           16 :         } else if (TRead::readProperty(g, tag, e, ctx, Pid::VIBRATO_LINE_TYPE)) {
    2819           16 :         } else if (TRead::readProperty(g, tag, e, ctx, Pid::GUITAR_DIVE_IS_SLACK)) {
    2820           16 :         } else if (!TRead::readProperties(static_cast<SLine*>(g), e, ctx)) {
    2821            0 :             e.unknown();
    2822              :         }
    2823              :     }
    2824            4 : }
    2825              : 
    2826            0 : void TRead::read(GuitarBendHold* h, XmlReader& xml, ReadContext& ctx)
    2827              : {
    2828            0 :     h->eraseSpannerSegments();
    2829              : 
    2830            0 :     while (xml.readNextStartElement()) {
    2831            0 :         if (!TRead::readProperties(static_cast<SLine*>(h), xml, ctx)) {
    2832            0 :             xml.unknown();
    2833              :         }
    2834              :     }
    2835            0 : }
    2836              : 
    2837            0 : bool TRead::readProperties(GuitarBendSegment* g, const AsciiStringView& tag, XmlReader& xml, ReadContext& ctx)
    2838              : {
    2839            0 :     if (tag == "bendVertexOffset") {
    2840            0 :         g->setVertexPointOff(xml.readPoint() * g->style().spatium());
    2841            0 :     } else if (tag == "GuitarBendText") {
    2842            0 :         GuitarBendText* bendText = new GuitarBendText(g);
    2843            0 :         read(toTextBase(bendText), xml, ctx);
    2844            0 :         g->setBendText(bendText);
    2845              :     } else {
    2846            0 :         return false;
    2847              :     }
    2848              : 
    2849            0 :     return true;
    2850              : }
    2851              : 
    2852           68 : void TRead::read(Hairpin* h, XmlReader& e, ReadContext& ctx)
    2853              : {
    2854           68 :     h->eraseSpannerSegments();
    2855              : 
    2856          480 :     while (e.readNextStartElement()) {
    2857          412 :         const AsciiStringView tag(e.name());
    2858          412 :         if (tag == "subtype") {
    2859           68 :             h->setHairpinType(HairpinType(e.readInt()));
    2860          344 :         } else if (tag == "hairpinCircledTip") {
    2861            0 :             h->setHairpinCircledTip(e.readInt());
    2862          344 :         } else if (tag == "veloChange") {
    2863            3 :             h->setVeloChange(e.readInt());
    2864          341 :         } else if (tag == "singleNoteDynamics") {
    2865            0 :             h->setSingleNoteDynamics(e.readBool());
    2866          341 :         } else if (tag == "veloChangeMethod") {
    2867            0 :             h->setVeloChangeMethod(TConv::fromXml(e.readAsciiText(), ChangeMethod::NORMAL));
    2868          341 :         } else if (readProperty(h, tag, e, ctx, Pid::VOICE_ASSIGNMENT)) {
    2869          341 :         } else if (readProperty(h, tag, e, ctx, Pid::DIRECTION)) {
    2870          341 :         } else if (readProperty(h, tag, e, ctx, Pid::CENTER_BETWEEN_STAVES)) {
    2871          341 :         } else if (readProperty(h, tag, e, ctx, Pid::SNAP_BEFORE)) {
    2872          341 :         } else if (readProperty(h, tag, e, ctx, Pid::SNAP_AFTER)) {
    2873          341 :         } else if (!readProperties(toTextLineBase(h), e, ctx)) {
    2874            0 :             e.unknown();
    2875              :         }
    2876              :     }
    2877           68 :     if (ctx.mscVersion() < 470) {
    2878            4 :         compat::CompatUtils::setTextLineTextPositionFromAlign(h);
    2879              :     }
    2880           68 :     h->styleChanged();
    2881           68 : }
    2882              : 
    2883            0 : void TRead::read(HammerOnPullOff* h, XmlReader& xml, ReadContext& ctx)
    2884              : {
    2885            0 :     while (xml.readNextStartElement()) {
    2886            0 :         if (!readProperties(toSlur(h), xml, ctx)) {
    2887            0 :             xml.unknown();
    2888              :         }
    2889              :     }
    2890            0 : }
    2891              : 
    2892           22 : static void readHarmonyInfo(HarmonyInfo* info, XmlReader& e)
    2893              : {
    2894           56 :     while (e.readNextStartElement()) {
    2895           34 :         const AsciiStringView tag(e.name());
    2896           34 :         if (tag == "bass") {
    2897            0 :             info->setBassTpc(e.readInt());
    2898           34 :         } else if (tag == "extension") {
    2899            0 :             info->setId(e.readInt());
    2900           34 :         } else if (tag == "name") {
    2901           12 :             info->setTextName(e.readText());
    2902           22 :         } else if (tag == "root") {
    2903           22 :             info->setRootTpc(e.readInt());
    2904              :         } else {
    2905            0 :             e.unknown();
    2906              :         }
    2907              :     }
    2908           22 : }
    2909              : 
    2910           22 : void TRead::read(Harmony* h, XmlReader& e, ReadContext& ctx)
    2911              : {
    2912           82 :     while (e.readNextStartElement()) {
    2913           60 :         const AsciiStringView tag(e.name());
    2914           60 :         if (tag == "bassCase") {
    2915            0 :             h->setBassCase(TConv::fromXml(e.readAsciiText(), NoteCaseType::AUTO));
    2916           60 :         } else if (tag == "rootCase") {
    2917            0 :             h->setRootCase(TConv::fromXml(e.readAsciiText(), NoteCaseType::AUTO));
    2918           60 :         } else if (tag == "harmonyInfo") {
    2919           22 :             HarmonyInfo* info = new HarmonyInfo(ctx.score());
    2920           22 :             readHarmonyInfo(info, e);
    2921           22 :             h->addChord(info);
    2922           38 :         } else if (tag == "degree") {
    2923            0 :             int degreeValue = 0;
    2924            0 :             int degreeAlter = 0;
    2925            0 :             String degreeType;
    2926            0 :             while (e.readNextStartElement()) {
    2927            0 :                 const AsciiStringView t(e.name());
    2928            0 :                 if (t == "degree-value") {
    2929            0 :                     degreeValue = e.readInt();
    2930            0 :                 } else if (t == "degree-alter") {
    2931            0 :                     degreeAlter = e.readInt();
    2932            0 :                 } else if (t == "degree-type") {
    2933            0 :                     degreeType = e.readText();
    2934              :                 } else {
    2935            0 :                     e.unknown();
    2936              :                 }
    2937              :             }
    2938            0 :             if (degreeValue <= 0 || degreeValue > 13
    2939            0 :                 || degreeAlter < -2 || degreeAlter > 2
    2940            0 :                 || (degreeType != "add" && degreeType != "alter" && degreeType != "subtract")) {
    2941            0 :                 LOGD("incorrect degree: degreeValue=%d degreeAlter=%d degreeType=%s",
    2942            0 :                      degreeValue, degreeAlter, muPrintable(degreeType));
    2943              :             } else {
    2944            0 :                 if (degreeType == "add") {
    2945            0 :                     h->addDegree(HDegree(degreeValue, degreeAlter, HDegreeType::ADD));
    2946            0 :                 } else if (degreeType == "alter") {
    2947            0 :                     h->addDegree(HDegree(degreeValue, degreeAlter, HDegreeType::ALTER));
    2948            0 :                 } else if (degreeType == "subtract") {
    2949            0 :                     h->addDegree(HDegree(degreeValue, degreeAlter, HDegreeType::SUBTRACT));
    2950              :                 }
    2951              :             }
    2952           38 :         } else if (TRead::readProperty(h, tag, e, ctx, Pid::POS_ABOVE)) {
    2953           38 :         } else if (TRead::readProperty(h, tag, e, ctx, Pid::HARMONY_TYPE)) {
    2954           38 :         } else if (TRead::readProperty(h, tag, e, ctx, Pid::PLAY)) {
    2955           38 :         } else if (TRead::readProperty(h, tag, e, ctx, Pid::HARMONY_VOICE_LITERAL)) {
    2956           38 :         } else if (TRead::readProperty(h, tag, e, ctx, Pid::HARMONY_VOICING)) {
    2957           38 :         } else if (TRead::readProperty(h, tag, e, ctx, Pid::HARMONY_DURATION)) {
    2958           38 :         } else if (TRead::readProperty(h, tag, e, ctx, Pid::HARMONY_BASS_SCALE)) {
    2959           38 :         } else if (TRead::readProperty(h, tag, e, ctx, Pid::HARMONY_DO_NOT_STACK_MODIFIERS)) {
    2960           38 :         } else if (TRead::readProperty(h, tag, e, ctx, Pid::EXCLUDE_VERTICAL_ALIGN)) {
    2961           38 :         } else if (!readProperties(toTextBase(h), e, ctx)) {
    2962            0 :             e.unknown();
    2963              :         }
    2964              :     }
    2965              : 
    2966           22 :     h->afterRead();
    2967           22 : }
    2968              : 
    2969           30 : void TRead::read(HarmonicMark* h, XmlReader& xml, ReadContext& ctx)
    2970              : {
    2971           30 :     TRead::read(toTextLineBase(h), xml, ctx);
    2972           30 : }
    2973              : 
    2974            7 : void TRead::read(HarpPedalDiagram* h, XmlReader& xml, ReadContext& ctx)
    2975              : {
    2976           40 :     while (xml.readNextStartElement()) {
    2977           33 :         const AsciiStringView tag = xml.name();
    2978           33 :         if (tag == "isDiagram") {
    2979            6 :             h->setIsDiagram(xml.readBool());
    2980           27 :         } else if (tag == "pedalState") {
    2981           56 :             while (xml.readNextStartElement()) {
    2982           49 :                 const AsciiStringView stringTag = xml.name();
    2983           49 :                 if (stringTag == "string") {
    2984           49 :                     HarpStringType str = HarpStringType(xml.intAttribute("name"));
    2985           49 :                     PedalPosition pos = PedalPosition(xml.readInt());
    2986           49 :                     h->setPedal(str, pos);
    2987              :                 } else {
    2988            0 :                     xml.unknown();
    2989              :                 }
    2990              :             }
    2991            7 :             h->setPlayableTpcs();
    2992           20 :         } else if (!readProperties(h, xml, ctx)) {
    2993            0 :             xml.unknown();
    2994              :         }
    2995              :     }
    2996            7 : }
    2997              : 
    2998            0 : void TRead::read(Hook* h, XmlReader& xml, ReadContext& ctx)
    2999              : {
    3000            0 :     TRead::read(static_cast<Symbol*>(h), xml, ctx);
    3001            0 : }
    3002              : 
    3003          103 : void TRead::read(LayoutBreak* b, XmlReader& e, ReadContext& ctx)
    3004              : {
    3005          313 :     while (e.readNextStartElement()) {
    3006          210 :         const AsciiStringView tag(e.name());
    3007          210 :         if (tag == "subtype") {
    3008          103 :             TRead::readProperty(b, e, ctx, Pid::LAYOUT_BREAK);
    3009          107 :         } else if (tag == "pause") {
    3010            0 :             TRead::readProperty(b, e, ctx, Pid::PAUSE);
    3011          107 :         } else if (tag == "startWithLongNames") {
    3012            0 :             TRead::readProperty(b, e, ctx, Pid::START_WITH_LONG_NAMES);
    3013          107 :         } else if (tag == "startWithMeasureOne") {
    3014            0 :             TRead::readProperty(b, e, ctx, Pid::START_WITH_MEASURE_ONE);
    3015          107 :         } else if (tag == "firstSystemIndentation") {
    3016            0 :             TRead::readProperty(b, e, ctx, Pid::FIRST_SYSTEM_INDENTATION);
    3017          107 :         } else if (tag == "showCourtesySig") {
    3018            0 :             TRead::readProperty(b, e, ctx, Pid::SHOW_COURTESY);
    3019          107 :         } else if (!readItemProperties(b, e, ctx)) {
    3020            0 :             e.unknown();
    3021              :         }
    3022              :     }
    3023          103 : }
    3024              : 
    3025            0 : void TRead::read(LedgerLine* l, XmlReader& e, ReadContext& ctx)
    3026              : {
    3027            0 :     while (e.readNextStartElement()) {
    3028            0 :         if (!readProperties(l, e, ctx)) {
    3029            0 :             e.unknown();
    3030              :         }
    3031              :     }
    3032            0 : }
    3033              : 
    3034            0 : bool TRead::readProperties(LedgerLine* l, XmlReader& e, ReadContext&)
    3035              : {
    3036            0 :     const AsciiStringView tag(e.name());
    3037              : 
    3038            0 :     if (tag == "lineWidth") {
    3039              :         //! NOTE Probably need to be removed, because it is calculated in Layout
    3040            0 :         LedgerLine::LayoutData* ldata = l->mutldata();
    3041            0 :         ldata->lineWidth = (e.readDouble() * l->spatium());
    3042            0 :     } else if (tag == "lineLen") {
    3043            0 :         l->setLen(e.readDouble() * l->spatium());
    3044            0 :     } else if (tag == "vertical") {
    3045            0 :         l->setVertical(e.readInt());
    3046              :     } else {
    3047            0 :         return false;
    3048              :     }
    3049            0 :     return true;
    3050              : }
    3051              : 
    3052           30 : void TRead::read(LetRing* r, XmlReader& e, ReadContext& ctx)
    3053              : {
    3054          210 :     while (e.readNextStartElement()) {
    3055          150 :         if (!readProperties(toTextLineBase(r), e, ctx)) {
    3056            0 :             e.unknown();
    3057              :         }
    3058              :     }
    3059           30 :     if (ctx.mscVersion() < 470) {
    3060            0 :         compat::CompatUtils::setTextLineTextPositionFromAlign(r);
    3061              :     }
    3062           30 : }
    3063              : 
    3064          132 : void TRead::read(Location* l, XmlReader& e, ReadContext&)
    3065              : {
    3066          232 :     while (e.readNextStartElement()) {
    3067          100 :         const AsciiStringView tag(e.name());
    3068              : 
    3069          100 :         if (tag == "staves") {
    3070            0 :             l->setStaff(e.readInt());
    3071          100 :         } else if (tag == "voices") {
    3072           11 :             l->setVoice(e.readInt());
    3073           89 :         } else if (tag == "measures") {
    3074            0 :             l->setMeasure(e.readInt());
    3075           89 :         } else if (tag == "fractions") {
    3076           89 :             l->setFrac(e.readFraction());
    3077            0 :         } else if (tag == "grace") {
    3078            0 :             l->setGraceIndex(e.readInt());
    3079            0 :         } else if (tag == "notes") {
    3080            0 :             l->setNote(e.readInt());
    3081            0 :         } else if (tag == "timeTick") {
    3082            0 :             l->setIsTimeTick(e.readBool());
    3083              :         } else {
    3084            0 :             e.unknown();
    3085              :         }
    3086              :     }
    3087          132 : }
    3088              : 
    3089           22 : void TRead::read(Lyrics* l, XmlReader& e, ReadContext& ctx)
    3090              : {
    3091          119 :     while (e.readNextStartElement()) {
    3092           75 :         if (!TRead::readProperties(l, e, ctx)) {
    3093            0 :             e.unknown();
    3094              :         }
    3095              :     }
    3096           22 : }
    3097              : 
    3098            1 : void TRead::read(LyricsLine* l, XmlReader& e, ReadContext& ctx)
    3099              : {
    3100            7 :     while (e.readNextStartElement()) {
    3101            5 :         if (!readProperties(static_cast<SLine*>(l), e, ctx)) {
    3102            0 :             e.unknown();
    3103              :         }
    3104              :     }
    3105            1 : }
    3106              : 
    3107            2 : void TRead::read(LineSegment* l, XmlReader& e, ReadContext& ctx)
    3108              : {
    3109           16 :     while (e.readNextStartElement()) {
    3110           12 :         if (!readProperties(l, e, ctx)) {
    3111            0 :             e.unknown();
    3112              :         }
    3113              :     }
    3114            2 : }
    3115              : 
    3116           12 : bool TRead::readProperties(LineSegment* l, XmlReader& e, ReadContext& ctx)
    3117              : {
    3118           12 :     const AsciiStringView tag(e.name());
    3119           12 :     if (tag == "subtype") {
    3120            2 :         l->setSpannerSegmentType(SpannerSegmentType(e.readInt()));
    3121           10 :     } else if (tag == "off2") {
    3122            2 :         l->setUserOff2(e.readPoint() * l->style().spatium());
    3123            8 :     } else if (l->isGuitarBendSegment() && readProperties(static_cast<GuitarBendSegment*>(l), tag, e, ctx)) {
    3124            8 :     } else if (!readItemProperties(l, e, ctx)) {
    3125            0 :         return false;
    3126              :     }
    3127           12 :     return true;
    3128              : }
    3129              : 
    3130           75 : bool TRead::readProperties(Lyrics* l, XmlReader& e, ReadContext& ctx)
    3131              : {
    3132           75 :     const AsciiStringView tag(e.name());
    3133              : 
    3134           75 :     if (tag == "no") {
    3135            1 :         l->setVerse(e.readInt());
    3136            1 :         if (l->isEven()) {
    3137            1 :             l->initTextStyleType(TextStyleType::LYRICS_EVEN);
    3138              :         }
    3139           74 :     } else if (tag == "syllabic") {
    3140           12 :         l->setSyllabic(TConv::fromXml(e.readAsciiText(), LyricsSyllabic::SINGLE));
    3141           62 :     } else if (tag == "ticks_f") {
    3142            6 :         l->setTicks(e.readFraction());
    3143           56 :     } else if (TRead::readProperty(l, tag, e, ctx, Pid::PLACEMENT)) {
    3144           56 :     } else if (tag == "LyricsLine") {
    3145            0 :         LyricsLine* ll = Factory::createLyricsLine(l);
    3146            0 :         TRead::read(ll, e, ctx);
    3147            0 :         ll->setTick(ctx.tick());
    3148            0 :         l->setSeparator(ll);
    3149            0 :         ctx.score()->addUnmanagedSpanner(ll);
    3150           56 :     } else if (!readProperties(toTextBase(l), e, ctx)) {
    3151            0 :         return false;
    3152              :     }
    3153           75 :     return true;
    3154              : }
    3155              : 
    3156           50 : void TRead::read(MeasureRepeat* r, XmlReader& e, ReadContext& ctx)
    3157              : {
    3158          271 :     while (e.readNextStartElement()) {
    3159          221 :         const AsciiStringView tag(e.name());
    3160          221 :         if (tag == "subtype") {
    3161           50 :             r->setNumMeasures(e.readInt());
    3162          171 :         } else if (TRead::readProperty(r, tag, e, ctx, Pid::MEASURE_REPEAT_NUMBER_OFFSET)) {
    3163          171 :         } else if (!readProperties(toRest(r), e, ctx)) {
    3164            0 :             e.unknown();
    3165              :         }
    3166              :     }
    3167           50 : }
    3168              : 
    3169           14 : void TRead::read(MMRest* r, XmlReader& e, ReadContext& ctx)
    3170              : {
    3171           71 :     while (e.readNextStartElement()) {
    3172           57 :         const AsciiStringView tag(e.name());
    3173           57 :         if (tag == "Symbol") {
    3174            0 :             Symbol* s = new Symbol(r);
    3175            0 :             s->setTrack(r->track());
    3176            0 :             TRead::read(s, e, ctx);
    3177            0 :             r->add(s);
    3178           57 :         } else if (tag == "Image") {
    3179            0 :             if (MScore::noImages) {
    3180            0 :                 e.skipCurrentElement();
    3181              :             } else {
    3182            0 :                 Image* image = new Image(r);
    3183            0 :                 image->setTrack(r->track());
    3184            0 :                 TRead::read(image, e, ctx);
    3185            0 :                 r->add(image);
    3186              :             }
    3187           57 :         } else if (tag == "NoteDot") {
    3188            0 :             NoteDot* dot = Factory::createNoteDot(r);
    3189            0 :             TRead::read(dot, e, ctx);
    3190            0 :             r->add(dot);
    3191           57 :         } else if (tag == "mmRestNumberPos") {
    3192              :             // Old property, deprecated in 4.5
    3193            0 :             r->setNumberOffset(Spatium(e.readDouble()) - ctx.style().styleS(Sid::mmRestNumberPos));
    3194           57 :         } else if (TRead::readProperty(r, tag, e, ctx, Pid::MMREST_NUMBER_OFFSET)) {
    3195           56 :         } else if (TRead::readStyledProperty(r, tag, e, ctx)) {
    3196           56 :         } else if (readProperties(r, e, ctx)) {
    3197              :         } else {
    3198            0 :             e.unknown();
    3199              :         }
    3200              :     }
    3201           14 : }
    3202              : 
    3203           56 : bool TRead::readProperties(MMRest* r, XmlReader& xml, ReadContext& ctx)
    3204              : {
    3205           56 :     const AsciiStringView tag(xml.name());
    3206           56 :     if (tag == "mmRestNumberVisible") {
    3207            0 :         r->setProperty(Pid::MMREST_NUMBER_VISIBLE, xml.readBool());
    3208           56 :     } else if (TRead::readProperties(toRest(r), xml, ctx)) {
    3209              :     } else {
    3210            0 :         return false;
    3211              :     }
    3212           56 :     return true;
    3213              : }
    3214              : 
    3215         3539 : void TRead::read(Note* n, XmlReader& e, ReadContext& ctx)
    3216              : {
    3217         3539 :     n->setTpc1(Tpc::TPC_INVALID);
    3218         3539 :     n->setTpc2(Tpc::TPC_INVALID);
    3219              : 
    3220        18381 :     while (e.readNextStartElement()) {
    3221        11303 :         if (TRead::readProperties(n, e, ctx)) {
    3222              :         } else {
    3223            0 :             e.unknown();
    3224              :         }
    3225              :     }
    3226              : 
    3227         3539 :     n->setupAfterRead(ctx.tick(), ctx.pasteMode());
    3228         3539 : }
    3229              : 
    3230        11303 : bool TRead::readProperties(Note* n, XmlReader& e, ReadContext& ctx)
    3231              : {
    3232        11303 :     const AsciiStringView tag(e.name());
    3233              : 
    3234        11303 :     if (tag == "pitch") {
    3235         3539 :         n->setPitch(clampPitch(e.readInt()), false);
    3236         7764 :     } else if (TRead::readProperty(n, tag, e, ctx, Pid::CENT_OFFSET)) {
    3237         7764 :     } else if (tag == "tpc") {
    3238         3539 :         int tpc = e.readInt();
    3239         3539 :         n->setTpc1(tpc);
    3240         3539 :         n->setTpc2(tpc);
    3241         4225 :     } else if (tag == "track") {          // for performance
    3242           15 :         n->setTrack(e.readInt());
    3243         4210 :     } else if (tag == "Accidental") {
    3244            9 :         Accidental* a = Factory::createAccidental(n);
    3245            9 :         a->setTrack(n->track());
    3246            9 :         TRead::read(a, e, ctx);
    3247            9 :         n->add(a);
    3248         4201 :     } else if (tag == "tpc2") {
    3249          136 :         n->setTpc2(e.readInt());
    3250         4065 :     } else if (tag == "small") {
    3251          194 :         n->setSmall(e.readInt());
    3252         3871 :     } else if (tag == "mirror") {
    3253            4 :         TRead::readProperty(n, e, ctx, Pid::MIRROR_HEAD);
    3254         3867 :     } else if (tag == "dotPosition") {
    3255            4 :         TRead::readProperty(n, e, ctx, Pid::DOT_POSITION);
    3256         3863 :     } else if (tag == "fixed") {
    3257            0 :         n->setFixed(e.readBool());
    3258         3863 :     } else if (tag == "fixedLine") {
    3259            0 :         n->setFixedLine(e.readInt());
    3260         3863 :     } else if (tag == "headScheme") {
    3261            3 :         TRead::readProperty(n, e, ctx, Pid::HEAD_SCHEME);
    3262         3860 :     } else if (tag == "head") {
    3263          181 :         TRead::readProperty(n, e, ctx, Pid::HEAD_GROUP);
    3264         3679 :     } else if (tag == "velocity") {
    3265          101 :         n->setUserVelocity(e.readInt());
    3266         3578 :     } else if (tag == "play") {
    3267            0 :         n->setPlay(e.readInt());
    3268         3578 :     } else if (tag == "tuning") {
    3269          103 :         n->setTuning(e.readDouble());
    3270         3475 :     } else if (tag == "fret") {
    3271          103 :         n->setFret(e.readInt());
    3272         3372 :     } else if (tag == "string") {
    3273          106 :         n->setString(e.readInt());
    3274         3266 :     } else if (tag == "ghost") {
    3275           98 :         n->setGhost(e.readInt());
    3276         3168 :     } else if (tag == "dead") {
    3277            0 :         n->setDeadNote(e.readInt());
    3278         3168 :     } else if (tag == "headType") {
    3279          106 :         TRead::readProperty(n, e, ctx, Pid::HEAD_TYPE);
    3280         3062 :     } else if (tag == "veloType") {
    3281            0 :         TRead::readProperty(n, e, ctx, Pid::VELO_TYPE);
    3282         3062 :     } else if (tag == "line") {
    3283            0 :         n->setLine(e.readInt());
    3284         3062 :     } else if (tag == "Fingering") {
    3285           10 :         Fingering* f = Factory::createFingering(n);
    3286           10 :         f->setTrack(n->track());
    3287           10 :         TRead::read(f, e, ctx);
    3288           10 :         n->add(f);
    3289         3052 :     } else if (tag == "Text") {
    3290            0 :         Text* t = Factory::createText(n);
    3291            0 :         t->setTrack(n->track());
    3292            0 :         TRead::read(t, e, ctx);
    3293            0 :         n->add(t);
    3294         3052 :     } else if (tag == "Symbol") {
    3295            7 :         Symbol* s = new Symbol(n);
    3296            7 :         s->setTrack(n->track());
    3297            7 :         TRead::read(s, e, ctx);
    3298            7 :         n->add(s);
    3299         3045 :     } else if (tag == "Image") {
    3300            0 :         if (MScore::noImages) {
    3301            0 :             e.skipCurrentElement();
    3302              :         } else {
    3303            0 :             Image* image = new Image(n);
    3304            0 :             image->setTrack(n->track());
    3305            0 :             TRead::read(image, e, ctx);
    3306            0 :             n->add(image);
    3307              :         }
    3308         3045 :     } else if (tag == "Bend") {
    3309            0 :         Bend* b = Factory::createBend(n);
    3310            0 :         b->setTrack(n->track());
    3311            0 :         TRead::read(b, e, ctx);
    3312            0 :         n->add(b);
    3313         3045 :     } else if (tag == "NoteDot") {
    3314            0 :         NoteDot* dot = Factory::createNoteDot(n);
    3315            0 :         TRead::read(dot, e, ctx);
    3316            0 :         n->add(dot);
    3317         3045 :     } else if (tag == "Events") {
    3318            0 :         NoteEventList playEvents;
    3319            0 :         while (e.readNextStartElement()) {
    3320            0 :             const AsciiStringView t(e.name());
    3321            0 :             if (t == "Event") {
    3322            0 :                 NoteEvent ne;
    3323            0 :                 TRead::read(&ne, e, ctx);
    3324            0 :                 playEvents.push_back(ne);
    3325              :             } else {
    3326            0 :                 e.unknown();
    3327              :             }
    3328              :         }
    3329            0 :         n->setPlayEvents(playEvents);
    3330            0 :         if (n->chord()) {
    3331            0 :             n->chord()->setPlayEventType(PlayEventType::User);
    3332              :         }
    3333         3045 :     } else if (tag == "offset") {
    3334            0 :         readItemProperties(n, e, ctx);
    3335         3045 :     } else if (tag == "ChordLine" && n->chord()) {
    3336            1 :         ChordLine* cl = Factory::createChordLine(n->chord());
    3337            1 :         TRead::read(cl, e, ctx);
    3338            1 :         cl->setNote(n);
    3339            1 :         n->chord()->add(cl);
    3340         3044 :     } else if (tag == "LaissezVib") {
    3341            1 :         LaissezVib* lv = Factory::createLaissezVib(n);
    3342            1 :         TRead::read(lv, e, ctx);
    3343            1 :         n->add(lv);
    3344         3043 :     } else if (tag == "PartialTie") {
    3345           18 :         PartialTie* pt = Factory::createPartialTie(n);
    3346           18 :         TRead::read(pt, e, ctx);
    3347           18 :         if (pt->isOutgoing()) {
    3348            6 :             pt->setStartNote(n);
    3349              :         } else {
    3350           12 :             pt->setEndNote(n);
    3351              :         }
    3352           18 :         n->add(pt);
    3353         3025 :     } else if (Spanner* spanner = tryCreateSpanner(tag, ctx, /*requireNoteAnchor*/ true)) {
    3354           41 :         TRead::readItem(spanner, e, ctx);
    3355         2984 :     } else if (tag == "overrideBendVisibilityRules") {
    3356            0 :         n->setOverrideBendVisibilityRules(e.readBool());
    3357         2984 :     } else if (TRead::readProperty(n, tag, e, ctx, Pid::HIDE_GENERATED_PARENTHESES)) {
    3358         2984 :     } else if (readItemProperties(n, e, ctx)) {
    3359              :     } else {
    3360            0 :         return false;
    3361              :     }
    3362        11303 :     return true;
    3363              : }
    3364              : 
    3365            0 : void TRead::read(NoteEvent* item, XmlReader& e, ReadContext&)
    3366              : {
    3367            0 :     while (e.readNextStartElement()) {
    3368            0 :         const AsciiStringView tag(e.name());
    3369            0 :         if (tag == "pitch") {
    3370            0 :             item->setPitch(e.readInt());
    3371            0 :         } else if (tag == "ontime") {
    3372            0 :             item->setOntime(e.readInt());
    3373            0 :         } else if (tag == "len") {
    3374            0 :             item->setLen(e.readInt());
    3375              :         } else {
    3376            0 :             e.unknown();
    3377              :         }
    3378              :     }
    3379            0 : }
    3380              : 
    3381            0 : void TRead::read(NoteDot* d, XmlReader& e, ReadContext& ctx)
    3382              : {
    3383            0 :     while (e.readNextStartElement()) {
    3384            0 :         if (!readItemProperties(d, e, ctx)) {
    3385            0 :             e.unknown();
    3386              :         }
    3387              :     }
    3388            0 : }
    3389              : 
    3390            0 : void TRead::read(NoteHead* h, XmlReader& xml, ReadContext& ctx)
    3391              : {
    3392            0 :     read(static_cast<Symbol*>(h), xml, ctx);
    3393            0 : }
    3394              : 
    3395            1 : void TRead::read(NoteLine* nl, XmlReader& xml, ReadContext& ctx)
    3396              : {
    3397            1 :     TRead::read(toTextLineBase(nl), xml, ctx);
    3398            1 : }
    3399              : 
    3400           41 : void TRead::read(Ottava* o, XmlReader& e, ReadContext& ctx)
    3401              : {
    3402           41 :     o->eraseSpannerSegments();
    3403          287 :     while (e.readNextStartElement()) {
    3404          246 :         readProperties(o, e, ctx);
    3405              :     }
    3406           41 :     if (ctx.mscVersion() < 470) {
    3407            2 :         compat::CompatUtils::setTextLineTextPositionFromAlign(o);
    3408              :     }
    3409           41 :     if (o->ottavaType() != OttavaType::OTTAVA_8VA || o->numbersOnly() != o->propertyDefault(Pid::NUMBERS_ONLY).toBool()) {
    3410            1 :         o->styleChanged();
    3411              :     }
    3412           41 : }
    3413              : 
    3414          246 : bool TRead::readProperties(Ottava* o, XmlReader& e, ReadContext& ctx)
    3415              : {
    3416          246 :     const AsciiStringView tag(e.name());
    3417          246 :     if (tag == "subtype") {
    3418           41 :         String s = e.readText();
    3419              :         bool ok;
    3420           41 :         int idx = s.toInt(&ok);
    3421           41 :         if (!ok) {
    3422           41 :             o->setOttavaType(OttavaType::OTTAVA_8VA);
    3423           41 :             for (OttavaDefault d : ottavaDefault) {
    3424           41 :                 if (s == d.name) {
    3425           41 :                     o->setOttavaType(d.type);
    3426           41 :                     break;
    3427              :                 }
    3428           41 :             }
    3429              :         } else {
    3430            0 :             o->setOttavaType(OttavaType(idx));
    3431              :         }
    3432          246 :     } else if (!readProperties(toTextLineBase(o), e, ctx)) {
    3433            0 :         e.unknown();
    3434            0 :         return false;
    3435              :     }
    3436          246 :     return true;
    3437              : }
    3438              : 
    3439            0 : void TRead::read(Page* p, XmlReader& e, ReadContext& ctx)
    3440              : {
    3441            0 :     while (e.readNextStartElement()) {
    3442            0 :         if (e.name() == "System") {
    3443            0 :             System* system = Factory::createSystem(p->score());
    3444            0 :             p->score()->systems().push_back(system);
    3445            0 :             read(system, e, ctx);
    3446              :         } else {
    3447            0 :             e.unknown();
    3448              :         }
    3449              :     }
    3450            0 : }
    3451              : 
    3452           38 : void TRead::read(PalmMute* p, XmlReader& e, ReadContext& ctx)
    3453              : {
    3454          266 :     while (e.readNextStartElement()) {
    3455          190 :         if (!readProperties(toTextLineBase(p), e, ctx)) {
    3456            0 :             e.unknown();
    3457              :         }
    3458              :     }
    3459           38 :     if (ctx.mscVersion() < 470) {
    3460            0 :         compat::CompatUtils::setTextLineTextPositionFromAlign(p);
    3461              :     }
    3462           38 : }
    3463              : 
    3464            6 : void TRead::read(Parenthesis* p, XmlReader& xml, ReadContext& ctx)
    3465              : {
    3466           15 :     while (xml.readNextStartElement()) {
    3467            9 :         const AsciiStringView tag(xml.name());
    3468            9 :         if (TRead::readProperty(p, tag, xml, ctx, Pid::HORIZONTAL_DIRECTION)) {
    3469            6 :         } else if (!readItemProperties(p, xml, ctx)) {
    3470            0 :             xml.unknown();
    3471              :         }
    3472              :     }
    3473            6 : }
    3474              : 
    3475          357 : void TRead::read(Part* p, XmlReader& e, ReadContext& ctx)
    3476              : {
    3477          357 :     p->setId(e.intAttribute("id", 0));
    3478              : 
    3479         1704 :     while (e.readNextStartElement()) {
    3480          990 :         if (!readProperties(p, e, ctx)) {
    3481            0 :             e.unknown();
    3482              :         }
    3483              :     }
    3484          357 : }
    3485              : 
    3486            1 : void TRead::read(SharedPart* p, XmlReader& e, ReadContext& ctx)
    3487              : {
    3488            1 :     p->setId(e.intAttribute("id", 0));
    3489              : 
    3490            6 :     while (e.readNextStartElement()) {
    3491            5 :         const AsciiStringView tag(e.name());
    3492            5 :         if (tag == "sharedPartEnabled") {
    3493            1 :             p->setProperty(Pid::SHARED_PART_ENABLED, e.readBool());
    3494            4 :         } else if (!readProperties(p, e, ctx)) {
    3495            0 :             e.unknown();
    3496              :         }
    3497              :     }
    3498            1 : }
    3499              : 
    3500            5 : void TRead::read(PartialLyricsLine* p, XmlReader& xml, ReadContext& ctx)
    3501              : {
    3502           36 :     while (xml.readNextStartElement()) {
    3503           31 :         const AsciiStringView tag(xml.name());
    3504           31 :         if (tag == "isEndMelisma") {
    3505            5 :             p->setIsEndMelisma(xml.readBool());
    3506           26 :         } else if (TRead::readProperty(p, tag, xml, ctx, Pid::VERSE)) {
    3507           26 :         } else if (TRead::readProperty(p, tag, xml, ctx, Pid::CENTER_BETWEEN_STAVES)) {
    3508           25 :         } else if (!readProperties(static_cast<SLine*>(p), xml, ctx)) {
    3509            0 :             xml.unknown();
    3510              :         }
    3511              :     }
    3512            5 : }
    3513              : 
    3514           18 : void TRead::read(PartialTie* p, XmlReader& xml, ReadContext& ctx)
    3515              : {
    3516           84 :     while (xml.readNextStartElement()) {
    3517           66 :         const AsciiStringView tag(xml.name());
    3518           66 :         if (TRead::readProperty(p, tag, xml, ctx, Pid::TIE_PLACEMENT)) {
    3519           66 :         } else if (TRead::readProperty(p, tag, xml, ctx, Pid::PARTIAL_SPANNER_DIRECTION)) {
    3520           54 :         } else if (!readProperties(toSlurTie(p), xml, ctx)) {
    3521            0 :             xml.unknown();
    3522              :         }
    3523              :     }
    3524           18 : }
    3525              : 
    3526          994 : bool TRead::readProperties(Part* p, XmlReader& e, ReadContext& ctx)
    3527              : {
    3528          994 :     const AsciiStringView tag(e.name());
    3529          994 :     if (tag == "id") {
    3530            0 :         p->setId(e.readInt());
    3531          994 :     } else if (tag == "eid") {
    3532          243 :         readItemEID(p, e, ctx);
    3533          751 :     } else if (tag == "sharedPart") {
    3534            2 :         AsciiStringView s = e.readAsciiText();
    3535            2 :         EID eid = EID::fromStdString(s);
    3536            2 :         DO_ASSERT(eid.isValid());
    3537            2 :         EIDRegister* eidRegister = ctx.score()->masterScore()->eidRegister();
    3538            2 :         EngravingObject* obj = eidRegister->itemFromEID(eid);
    3539            2 :         DO_ASSERT(obj && obj->isSharedPart());
    3540            2 :         SharedPart* sharedPart = toSharedPart(obj);
    3541            2 :         sharedPart->addOriginPart(p);
    3542          749 :     } else if (tag == "Staff") {
    3543          389 :         Staff* staff = Factory::createStaff(p);
    3544          389 :         p->score()->appendStaff(staff);
    3545          389 :         TRead::read(staff, e, ctx);
    3546          360 :     } else if (tag == "Instrument") {
    3547          358 :         Instrument* instr = new Instrument;
    3548          358 :         read(instr, e, ctx, p);
    3549          358 :         p->setInstrument(instr, Fraction(-1, 1));
    3550            2 :     } else if (tag == "name") {
    3551            0 :         p->instrument()->setLongName(e.readText());
    3552            2 :     } else if (tag == "color") {
    3553            0 :         e.skipCurrentElement(); // Unused
    3554            2 :     } else if (tag == "shortName") {
    3555            0 :         p->instrument()->setShortName(e.readText());
    3556            2 :     } else if (tag == "show") {
    3557            2 :         p->setShow(e.readInt());
    3558            0 :     } else if (tag == "soloist") {
    3559            0 :         p->setSoloist(e.readInt());
    3560            0 :     } else if (tag == "hideWhenEmpty") {
    3561            0 :         p->setHideWhenEmpty(TConv::fromXml(e.readAsciiText(), AutoOnOff::AUTO));
    3562            0 :     } else if (tag == "hideStavesWhenIndividuallyEmpty") {
    3563            0 :         p->setHideStavesWhenIndividuallyEmpty(e.readBool());
    3564            0 :     } else if (tag == "preferSharpFlat") {
    3565            0 :         String val = e.readText();
    3566            0 :         if (val == "sharps") {
    3567            0 :             p->setPreferSharpFlat(PreferSharpFlat::SHARPS);
    3568            0 :         } else if (val == "flats") {
    3569            0 :             p->setPreferSharpFlat(PreferSharpFlat::FLATS);
    3570            0 :         } else if (val == "none") {
    3571            0 :             p->setPreferSharpFlat(PreferSharpFlat::NONE);
    3572              :         } else {
    3573            0 :             p->setPreferSharpFlat(PreferSharpFlat::AUTO);
    3574              :         }
    3575            0 :     } else {
    3576            0 :         return false;
    3577              :     }
    3578          994 :     return true;
    3579              : }
    3580              : 
    3581           41 : void TRead::read(Pedal* p, XmlReader& e, ReadContext& ctx)
    3582              : {
    3583           41 :     bool beginTextTag = false;
    3584           41 :     bool continueTextTag = false;
    3585           41 :     bool endTextTag = false;
    3586              : 
    3587          329 :     while (e.readNextStartElement()) {
    3588          288 :         const AsciiStringView tag(e.name());
    3589          288 :         beginTextTag = beginTextTag || tag == "beginText";
    3590          288 :         continueTextTag = continueTextTag || tag == "continueText";
    3591          288 :         endTextTag = endTextTag || tag == "endText";
    3592              : 
    3593          288 :         if (TRead::readProperty(p, tag, e, ctx, Pid::LINE_VISIBLE)) {
    3594            0 :             p->resetProperty(Pid::END_TEXT);
    3595          288 :         } else if (TRead::readProperty(p, tag, e, ctx, Pid::BEGIN_HOOK_TYPE)) {
    3596            0 :             if (p->beginHookType() != HookType::NONE) {
    3597            0 :                 p->setBeginText(String());
    3598            0 :                 p->setContinueText(String());
    3599              :             }
    3600          288 :         } else if (!readProperties(toTextLineBase(p), e, ctx)) {
    3601            0 :             e.unknown();
    3602              :         }
    3603              :     }
    3604           41 :     if (ctx.mscVersion() < 470) {
    3605            1 :         compat::CompatUtils::setTextLineTextPositionFromAlign(p);
    3606              : 
    3607            1 :         if (p->endText() == Pedal::STAR_SYMBOL) {
    3608            0 :             p->setEndHookType(HookType::ROSETTE);
    3609              :         }
    3610              :     }
    3611           41 : }
    3612              : 
    3613           30 : void TRead::read(Rasgueado* r, XmlReader& xml, ReadContext& ctx)
    3614              : {
    3615           30 :     TRead::read(toTextLineBase(r), xml, ctx);
    3616           30 : }
    3617              : 
    3618         6417 : void TRead::read(Rest* r, XmlReader& e, ReadContext& ctx)
    3619              : {
    3620        26873 :     while (e.readNextStartElement()) {
    3621        20456 :         const AsciiStringView tag(e.name());
    3622        20456 :         if (tag == "NoteDot") {
    3623            0 :             NoteDot* dot = Factory::createNoteDot(r);
    3624            0 :             TRead::read(dot, e, ctx);
    3625            0 :             r->add(dot);
    3626        20456 :         } else if (TRead::readStyledProperty(r, tag, e, ctx)) {
    3627        20456 :         } else if (TRead::readProperty(r, tag, e, ctx, Pid::ALIGN_WITH_OTHER_RESTS)) {
    3628        20456 :         } else if (TRead::readProperties(r, e, ctx)) {
    3629              :         } else {
    3630            0 :             e.unknown();
    3631              :         }
    3632              :     }
    3633         6417 : }
    3634              : 
    3635            0 : void TRead::read(Segment* s, XmlReader& e, ReadContext& ctx)
    3636              : {
    3637              :     UNUSED(ctx);
    3638            0 :     while (e.readNextStartElement()) {
    3639            0 :         const AsciiStringView tag(e.name());
    3640              : 
    3641            0 :         if (tag == "subtype") {
    3642            0 :             e.skipCurrentElement();
    3643            0 :         } else if (tag == "leadingSpace") {
    3644            0 :             s->setExtraLeadingSpace(Spatium(e.readDouble()));
    3645              :         } else {
    3646            0 :             e.unknown();
    3647              :         }
    3648              :     }
    3649            0 : }
    3650              : 
    3651            0 : void TRead::read(SLine* l, XmlReader& e, ReadContext& ctx)
    3652              : {
    3653            0 :     l->eraseSpannerSegments();
    3654              : 
    3655            0 :     while (e.readNextStartElement()) {
    3656            0 :         if (!readProperties(l, e, ctx)) {
    3657            0 :             e.unknown();
    3658              :         }
    3659              :     }
    3660            0 : }
    3661              : 
    3662         1742 : bool TRead::readProperties(SLine* l, XmlReader& e, ReadContext& ctx)
    3663              : {
    3664         1742 :     const AsciiStringView tag(e.name());
    3665              : 
    3666         1742 :     if (tag == "Segment") {
    3667            2 :         LineSegment* ls = l->createLineSegment();
    3668            2 :         ls->setTrack(l->track());     // needed in read to get the right staff mag
    3669            2 :         l->add(ls);
    3670            2 :         TRead::read(ls, e, ctx);
    3671            2 :         ls->setVisible(l->visible());
    3672         1740 :     } else if (TRead::readStyledProperty(l, tag, e, ctx)) {
    3673         1678 :     } else if (TRead::readProperty(l, tag, e, ctx, Pid::DIAGONAL)) {
    3674         1673 :     } else if (TRead::readProperty(l, tag, e, ctx, Pid::LINE_WIDTH)) {
    3675         1672 :     } else if (TRead::readProperty(l, tag, e, ctx, Pid::LINE_STYLE)) {
    3676         1672 :     } else if (TRead::readProperty(l, tag, e, ctx, Pid::DASH_LINE_LEN)) {
    3677         1672 :     } else if (TRead::readProperty(l, tag, e, ctx, Pid::DASH_GAP_LEN)) {
    3678         1672 :     } else if (tag == "lineColor" || tag == "color") {
    3679            0 :         l->setLineColor(e.readColor());
    3680         1672 :     } else if (!readProperties(toSpanner(l), e, ctx)) {
    3681            0 :         return false;
    3682              :     }
    3683         1742 :     return true;
    3684              : }
    3685              : 
    3686           30 : void TRead::read(Slur* s, XmlReader& e, ReadContext& ctx)
    3687              : {
    3688          184 :     while (e.readNextStartElement()) {
    3689          124 :         if (!readProperties(s, e, ctx)) {
    3690            0 :             e.unknown();
    3691              :         }
    3692              :     }
    3693           30 : }
    3694              : 
    3695          124 : bool TRead::readProperties(Slur* s, XmlReader& e, ReadContext& ctx)
    3696              : {
    3697          124 :     const AsciiStringView tag(e.name());
    3698              : 
    3699          124 :     if (TRead::readProperty(s, tag, e, ctx, Pid::PARTIAL_SPANNER_DIRECTION)) {
    3700            9 :         return true;
    3701              :     }
    3702              : 
    3703          115 :     return readProperties(toSlurTie(s), e, ctx);
    3704              : }
    3705              : 
    3706            0 : void TRead::read(SlurTie* s, XmlReader& e, ReadContext& ctx)
    3707              : {
    3708            0 :     while (e.readNextStartElement()) {
    3709            0 :         if (!readProperties(s, e, ctx)) {
    3710            0 :             e.unknown();
    3711              :         }
    3712              :     }
    3713            0 : }
    3714              : 
    3715          300 : bool TRead::readProperties(SlurTie* s, XmlReader& e, ReadContext& ctx)
    3716              : {
    3717          300 :     const AsciiStringView tag(e.name());
    3718              : 
    3719          300 :     if (TRead::readProperty(s, tag, e, ctx, Pid::SLUR_DIRECTION)) {
    3720          298 :     } else if (TRead::readProperty(s, tag, e, ctx, Pid::MASK_SLURTIE)) {
    3721          298 :     } else if (tag == "lineType") {
    3722            3 :         s->setStyleType(static_cast<SlurStyleType>(e.readInt()));
    3723          587 :     } else if (tag == "SlurSegment" || tag == "TieSegment" || tag == "LaissezVibSegment" || tag == "PartialTieSegment"
    3724          587 :                || tag == "HammerOnPullOffSegment" || tag == "TappingHalfSlurSegment") {
    3725            3 :         const int idx = e.intAttribute("no", 0);
    3726            3 :         const int n = int(s->spannerSegments().size());
    3727            4 :         for (int i = n; i < idx; ++i) {
    3728            1 :             s->add(s->newSlurTieSegment());
    3729              :         }
    3730            3 :         SlurTieSegment* sts = s->newSlurTieSegment();
    3731            3 :         s->add(sts);
    3732            3 :         TRead::read(sts, e, ctx);
    3733          292 :     } else if (!readProperties(toSpanner(s), e, ctx)) {
    3734            0 :         return false;
    3735              :     }
    3736          300 :     return true;
    3737              : }
    3738              : 
    3739            3 : void TRead::read(SlurTieSegment* s, XmlReader& e, ReadContext& ctx)
    3740              : {
    3741           17 :     while (e.readNextStartElement()) {
    3742           14 :         const AsciiStringView tag(e.name());
    3743           14 :         if (readProperty(s, tag, e, ctx, Pid::BEZIER_OFFSET1)) {
    3744           14 :         } else if (readProperty(s, tag, e, ctx, Pid::BEZIER_OFFSET2)) {
    3745           11 :         } else if (readProperty(s, tag, e, ctx, Pid::BEZIER_OFFSET3)) {
    3746            9 :         } else if (readProperty(s, tag, e, ctx, Pid::BEZIER_OFFSET4)) {
    3747            9 :         } else if (tag == "HammerOnPullOffText") {
    3748            0 :             DO_ASSERT(s->isHammerOnPullOffSegment());
    3749            0 :             readHopoText(toHammerOnPullOffSegment(s), e, ctx, e.intAttribute("idx"));
    3750            9 :         } else if (!readItemProperties(s, e, ctx)) {
    3751            0 :             e.unknown();
    3752              :         }
    3753              :     }
    3754            3 : }
    3755              : 
    3756            0 : void TRead::readHopoText(HammerOnPullOffSegment* hopoSeg, XmlReader& xml, ReadContext& ctx, int idx)
    3757              : {
    3758            0 :     int hopoTextCount = static_cast<int>(hopoSeg->hopoText().size());
    3759            0 :     for (int i = hopoTextCount; i < idx; ++i) {
    3760            0 :         hopoSeg->addHopoText(new HammerOnPullOffText(hopoSeg));
    3761              :     }
    3762              : 
    3763            0 :     HammerOnPullOffText* hopoText = new HammerOnPullOffText(hopoSeg);
    3764            0 :     while (xml.readNextStartElement()) {
    3765            0 :         if (!readProperties(toTextBase(hopoText), xml, ctx)) {
    3766            0 :             xml.unknown();
    3767              :         }
    3768              :     }
    3769              : 
    3770            0 :     hopoSeg->addHopoText(hopoText);
    3771            0 : }
    3772              : 
    3773         3429 : String TRead::lineBreakFromTag(const String& str)
    3774              : {
    3775              :     // Raw newlines appearing next to tags (<font size="10> or <sym>...) get eaten by XML readers.
    3776         3429 :     String s = str;
    3777         6858 :     return s.replace(u"<br/>", u"\n");
    3778         3429 : }
    3779              : 
    3780            3 : void TRead::readNoteParenGroup(Chord* ch, XmlReader& e, ReadContext& ctx)
    3781              : {
    3782            3 :     Parenthesis* leftParen = nullptr;
    3783            3 :     Parenthesis* rightParen = nullptr;
    3784            3 :     std::vector<Note*> notes;
    3785           12 :     while (e.readNextStartElement()) {
    3786            9 :         const AsciiStringView t(e.name());
    3787              : 
    3788            9 :         if (t == "Parenthesis") {
    3789            6 :             Parenthesis* paren = Factory::createParenthesis(ch);
    3790            6 :             TRead::read(paren, e, ctx);
    3791            6 :             paren->setTrack(ctx.track());
    3792              : 
    3793            6 :             if (paren->direction() == DirectionH::LEFT) {
    3794            3 :                 leftParen = paren;
    3795              :             } else {
    3796            3 :                 rightParen = paren;
    3797              :             }
    3798            3 :         } else if (t == "Notes") {
    3799            6 :             while (e.readNextStartElement()) {
    3800            3 :                 const AsciiStringView noteTag(e.name());
    3801            3 :                 if (noteTag == "NoteEID") {
    3802            3 :                     AsciiStringView s = e.readAsciiText();
    3803            3 :                     EID eid = EID::fromStdString(s);
    3804            3 :                     IF_ASSERT_FAILED(eid.isValid()) {
    3805            0 :                         continue;
    3806              :                     }
    3807            3 :                     if (ctx.pasteMode()) {
    3808            1 :                         eid = ctx.resolvePastedEID(eid);
    3809              :                     }
    3810            3 :                     EIDRegister* eidRegister = ctx.score()->masterScore()->eidRegister();
    3811            3 :                     EngravingObject* obj = eidRegister->itemFromEID(eid);
    3812            3 :                     IF_ASSERT_FAILED(obj && obj->isNote()) {
    3813            0 :                         continue;
    3814              :                     }
    3815            3 :                     notes.push_back(toNote(obj));
    3816              :                 } else {
    3817            0 :                     e.unknown();
    3818              :                 }
    3819              :             }
    3820              :         } else {
    3821            0 :             e.unknown();
    3822              :         }
    3823              :     }
    3824              : 
    3825            3 :     if (!leftParen) {
    3826            0 :         leftParen = Factory::createParenthesis(ch);
    3827            0 :         leftParen->setTrack(ctx.track());
    3828              :     }
    3829              : 
    3830            3 :     if (!rightParen) {
    3831            0 :         rightParen = Factory::createParenthesis(ch);
    3832            0 :         rightParen->setDirection(DirectionH::RIGHT);
    3833            0 :         rightParen->setTrack(ctx.track());
    3834              :     }
    3835              : 
    3836            3 :     NoteParenthesisInfo* noteParenInfo = new NoteParenthesisInfo(leftParen, rightParen, notes);
    3837            3 :     ch->addNoteParenthesisInfo(noteParenInfo);
    3838            3 : }
    3839              : 
    3840         1964 : bool TRead::readProperties(Spanner* s, XmlReader& e, ReadContext& ctx)
    3841              : {
    3842         1964 :     const AsciiStringView tag(e.name());
    3843         1964 :     if (tag == "play") {
    3844            0 :         s->setPlaySpanner(e.readBool());
    3845            0 :         return true;
    3846         1964 :     } else if (tag == "track2") {
    3847          396 :         track_idx_t track2 = e.readInt();
    3848          396 :         s->setTrack2(track2 + ctx.trackOffset());
    3849         1568 :     } else if (tag == "startTick") {
    3850          396 :         Fraction startTick = e.readFraction() + ctx.tickOffset();
    3851          396 :         s->setTick(startTick);
    3852         1172 :     } else if (tag == "ticks") {
    3853           36 :         Fraction ticks = e.readFraction();
    3854           36 :         s->setTicks(ticks);
    3855         1136 :     } else if (tag == "startElement") {
    3856           85 :         EIDRegister* eidRegister = ctx.score()->masterScore()->eidRegister();
    3857           85 :         EID startElEID = EID::fromStdString(e.readAsciiText());
    3858           85 :         IF_ASSERT_FAILED(startElEID.isValid()) {
    3859           41 :             return false;
    3860              :         }
    3861           85 :         if (ctx.pasteMode()) {
    3862           36 :             startElEID = ctx.resolvePastedEID(startElEID);
    3863              :         }
    3864           85 :         if (s->anchor() == Spanner::Anchor::NOTE && !(s->isPartialTie() || s->isLaissezVib())) {
    3865              :             // Store spanner and EIDs to be connected at the end of file reading
    3866           41 :             ctx.addNoteAnchoredSpannerStartEl(s, startElEID);
    3867           41 :             return true;
    3868              :         }
    3869              : 
    3870           44 :         EngravingItem* startEl = toEngravingItem(eidRegister->itemFromEID(startElEID));
    3871           44 :         IF_ASSERT_FAILED(startEl) {
    3872            0 :             return false;
    3873              :         }
    3874           44 :         s->setStartElement(startEl);
    3875           44 :         s->setTick(startEl->tick());
    3876           44 :         s->setTrack(startEl->track());
    3877         1051 :     } else if (tag == "endElement") {
    3878           90 :         EIDRegister* eidRegister = ctx.score()->masterScore()->eidRegister();
    3879           90 :         EID endElEID = EID::fromStdString(e.readAsciiText());
    3880           90 :         IF_ASSERT_FAILED(endElEID.isValid()) {
    3881           41 :             return false;
    3882              :         }
    3883           90 :         if (ctx.pasteMode()) {
    3884           36 :             endElEID = ctx.resolvePastedEID(endElEID);
    3885              :         }
    3886           90 :         if (s->anchor() == Spanner::Anchor::NOTE && !(s->isPartialTie() || s->isLaissezVib())) {
    3887              :             // Store spanner and EIDs to be connected at the end of file reading
    3888           41 :             ctx.addNoteAnchoredSpannerEndEl(s, endElEID);
    3889           41 :             return true;
    3890              :         }
    3891              : 
    3892           49 :         EngravingItem* endEl = toEngravingItem(eidRegister->itemFromEID(endElEID));
    3893           49 :         IF_ASSERT_FAILED(endEl) {
    3894            0 :             return false;
    3895              :         }
    3896           49 :         s->setEndElement(endEl);
    3897           49 :         if (s->anchor() == Spanner::Anchor::MEASURE) {
    3898            7 :             s->setTick2(s->endMeasure()->endTick());
    3899              :         } else {
    3900           42 :             s->setTick2(endEl->tick());
    3901           42 :             s->setTrack2(endEl->track());
    3902              :         }
    3903          961 :     } else if (!readItemProperties(s, e, ctx)) {
    3904            0 :         return false;
    3905              :     }
    3906         1882 :     return true;
    3907              : }
    3908              : 
    3909            0 : void TRead::read(Spacer* s, XmlReader& e, ReadContext& ctx)
    3910              : {
    3911            0 :     while (e.readNextStartElement()) {
    3912            0 :         const AsciiStringView tag(e.name());
    3913            0 :         if (tag == "subtype") {
    3914            0 :             s->setSpacerType(SpacerType(e.readInt()));
    3915            0 :         } else if (tag == "space") {
    3916            0 :             s->setGap(Spatium(e.readDouble()));
    3917            0 :         } else if (!readItemProperties(s, e, ctx)) {
    3918            0 :             e.unknown();
    3919              :         }
    3920              :     }
    3921            0 : }
    3922              : 
    3923          389 : void TRead::read(StaffType* t, XmlReader& e, ReadContext& ctx)
    3924              : {
    3925          389 :     t->setScore(ctx.score());
    3926          389 :     t->setGroup(TConv::fromXml(e.asciiAttribute("group"), StaffGroup::STANDARD));
    3927              : 
    3928          389 :     if (t->group() == StaffGroup::TAB) {
    3929            2 :         t->setGenKeysig(false);
    3930              :     }
    3931              : 
    3932          821 :     while (e.readNextStartElement()) {
    3933          432 :         const AsciiStringView tag(e.name());
    3934          432 :         if (tag == "name") {
    3935          388 :             t->setType(TConv::fromXml(e.readAsciiText(), StaffTypes::STANDARD));
    3936           44 :         } else if (tag == "StaffLabel") {
    3937            0 :             StaffLabel& staffLabel = t->staffLabel();
    3938            0 :             readStaffLabel(staffLabel, e);
    3939           44 :         } else if (tag == "lines") {
    3940            2 :             t->setLines(e.readInt());
    3941           42 :         } else if (tag == "lineDistance") {
    3942            2 :             t->setLineDistance(Spatium(e.readDouble()));
    3943           40 :         } else if (tag == "yoffset") {
    3944            0 :             t->setYoffset(Spatium(e.readDouble()));
    3945           40 :         } else if (tag == "mag") {
    3946            0 :             t->setUserMag(e.readDouble());
    3947           40 :         } else if (tag == "small") {
    3948            0 :             t->setSmall(e.readBool());
    3949           40 :         } else if (tag == "stepOffset") {
    3950            0 :             t->setStepOffset(e.readInt());
    3951           40 :         } else if (tag == "clef") {
    3952            0 :             t->setGenClef(e.readInt());
    3953           40 :         } else if (tag == "stemless") {
    3954            2 :             bool val = e.readInt() != 0;
    3955            2 :             t->setStemless(val);
    3956            2 :             t->setShowBackTied(!val);        // for compatibility with 2.0.2 scores where this prop
    3957              :         }                                 // was lacking and controlled by "slashStyle" instead
    3958           38 :         else if (tag == "barlines") {
    3959            0 :             t->setShowBarlines(e.readInt());
    3960           38 :         } else if (tag == "timesig") {
    3961            2 :             t->setGenTimesig(e.readInt());
    3962           36 :         } else if (tag == "noteheadScheme") {
    3963            0 :             t->setNoteHeadScheme(TConv::fromXml(e.readAsciiText(), NoteHeadScheme::HEAD_NORMAL));
    3964           36 :         } else if (tag == "instrumentLabelVisibility") {
    3965            0 :             t->setInstrumentLabelVisibility(TConv::fromXml(e.readAsciiText(), InstrumentLabelVisibility::AUTO));
    3966           36 :         } else if (tag == "keysig") {
    3967            0 :             t->setGenKeysig(e.readInt());
    3968           36 :         } else if (tag == "ledgerlines") {
    3969            0 :             t->setShowLedgerLines(e.readInt());
    3970           36 :         } else if (tag == "invisible") {
    3971            0 :             t->setInvisible(e.readInt());
    3972           36 :         } else if (tag == "color") {
    3973            0 :             t->setColor(e.readColor());
    3974           36 :         } else if (tag == "durations") {
    3975            2 :             t->setGenDurations(e.readBool());
    3976           34 :         } else if (tag == "durationFontName") {
    3977            2 :             t->setDurationFontName(e.readText());
    3978           32 :         } else if (tag == "durationFontSize") {
    3979            2 :             t->setDurationFontSize(e.readDouble());
    3980           30 :         } else if (tag == "durationFontY") {
    3981            2 :             t->setDurationFontUserY(e.readDouble());
    3982           28 :         } else if (tag == "fretPresetIdx") {
    3983            2 :             t->setFretPresetIdx(e.readInt());
    3984           26 :         } else if (tag == "fretFontSize") {
    3985            2 :             t->setFretFontSize(e.readDouble());
    3986           24 :         } else if (tag == "fretFontY") {
    3987            2 :             t->setFretFontUserY(e.readDouble());
    3988           22 :         } else if (tag == "fretUseTextStyle") {
    3989            2 :             t->setFretUseTextStyle(e.readBool());
    3990           20 :         } else if (tag == "fretTextStyle") {
    3991            0 :             t->setFretTextStyle(TextStyleType(TConv::fromXml(e.readAsciiText(), TextStyleType::TAB_FRET_NUMBER)));
    3992           20 :         } else if (tag == "symbolRepeat") {
    3993            2 :             t->setSymbolRepeat((TablatureSymbolRepeat)e.readInt());
    3994           18 :         } else if (tag == "linesThrough") {
    3995            2 :             t->setLinesThrough(e.readBool());
    3996           16 :         } else if (tag == "minimStyle") {
    3997            2 :             t->setMinimStyle((TablatureMinimStyle)e.readInt());
    3998           14 :         } else if (tag == "onLines") {
    3999            2 :             t->setOnLines(e.readBool());
    4000           12 :         } else if (tag == "showRests") {
    4001            2 :             t->setShowRests(e.readBool());
    4002           10 :         } else if (tag == "stemsDown") {
    4003            2 :             t->setStemsDown(e.readBool());
    4004            8 :         } else if (tag == "stemsThrough") {
    4005            2 :             t->setStemsThrough(e.readBool());
    4006            6 :         } else if (tag == "upsideDown") {
    4007            2 :             t->setUpsideDown(e.readBool());
    4008            4 :         } else if (tag == "showTabFingering") {
    4009            0 :             t->setShowTabFingering(e.readBool());
    4010            4 :         } else if (tag == "useNumbers") {
    4011            2 :             t->setUseNumbers(e.readBool());
    4012            2 :         } else if (tag == "showBackTied") {           // must be after reading "slashStyle"/"stemless" prop, as in older
    4013            2 :             t->setShowBackTied(e.readBool());            // scores, this prop was lacking and controlled by "slashStyle"
    4014              :         } else {
    4015            0 :             e.unknown();
    4016              :         }
    4017              :     }
    4018          389 : }
    4019              : 
    4020            0 : void TRead::read(StaffTypeChange* c, XmlReader& e, ReadContext& ctx)
    4021              : {
    4022            0 :     while (e.readNextStartElement()) {
    4023            0 :         const AsciiStringView tag(e.name());
    4024            0 :         if (tag == "StaffType") {
    4025            0 :             StaffType* st = new StaffType();
    4026            0 :             TRead::read(st, e, ctx);
    4027              :             // Measure::add() will replace this with a pointer to a copy in the staff
    4028            0 :             c->setStaffType(st, true);
    4029            0 :         } else if (!readItemProperties(c, e, ctx)) {
    4030            0 :             e.unknown();
    4031              :         }
    4032              :     }
    4033            0 : }
    4034              : 
    4035          389 : void TRead::read(Staff* s, XmlReader& e, ReadContext& ctx)
    4036              : {
    4037         1585 :     while (e.readNextStartElement()) {
    4038          807 :         if (!readProperties(s, e, ctx)) {
    4039            0 :             e.unknown();
    4040              :         }
    4041              :     }
    4042          389 : }
    4043              : 
    4044          807 : bool TRead::readProperties(Staff* s, XmlReader& e, ReadContext& ctx)
    4045              : {
    4046          807 :     const AsciiStringView tag(e.name());
    4047          807 :     if (tag == "StaffType") {
    4048          389 :         StaffType st;
    4049          389 :         TRead::read(&st, e, ctx);
    4050          389 :         s->setStaffType(Fraction(0, 1), st);
    4051          807 :     } else if (tag == "defaultClef") {           // sets both default transposing and concert clef
    4052           12 :         ClefType ct = TConv::fromXml(e.readAsciiText(), ClefType::G);
    4053           12 :         s->setDefaultClefType(ClefTypeList(ct, ct));
    4054          406 :     } else if (tag == "defaultConcertClef") {
    4055            0 :         s->setDefaultClefType(ClefTypeList(TConv::fromXml(e.readAsciiText(), ClefType::G), s->defaultClefType().transposingClef));
    4056          406 :     } else if (tag == "defaultTransposingClef") {
    4057            0 :         s->setDefaultClefType(ClefTypeList(s->defaultClefType().concertClef, TConv::fromXml(e.readAsciiText(), ClefType::G)));
    4058          406 :     } else if (tag == "invisible") {
    4059            0 :         s->staffType(Fraction(0, 1))->setInvisible(e.readInt());              // same as: setInvisible(Fraction(0,1)), e.readInt())
    4060          406 :     } else if (tag == "hideWhenEmpty") {
    4061            0 :         s->setHideWhenEmpty(TConv::fromXml(e.readAsciiText(), AutoOnOff::AUTO));
    4062          406 :     } else if (tag == "cutaway") {
    4063            0 :         s->setCutaway(e.readInt());
    4064          406 :     } else if (tag == "showIfSystemEmpty") {
    4065            0 :         s->setShowIfEntireSystemEmpty(e.readInt());
    4066          406 :     } else if (tag == "hideSystemBarLine") {
    4067            0 :         s->setHideSystemBarLine(e.readInt());
    4068          406 :     } else if (tag == "mergeMatchingRests") {
    4069            0 :         s->setMergeMatchingRests(TConv::fromXml(e.readAsciiText(), AutoOnOff::AUTO));
    4070          406 :     } else if (tag == "isStaffVisible") {
    4071            0 :         s->setVisible(e.readBool());
    4072          406 :     } else if (tag == "keylist") {
    4073            0 :         TRead::read(s->keyList(), e, ctx);
    4074          406 :     } else if (tag == "bracket") { // LEGACY
    4075            0 :         Color color = Color::fromString(e.attribute("color"));
    4076            0 :         int col = e.intAttribute("col", -1);
    4077            0 :         if (col == -1) {
    4078            0 :             col = static_cast<int>(ctx.score()->brackets(s->idx()).size());
    4079              :         }
    4080            0 :         EditStaffBrackets::setBracketType(ctx.score(), s->idx(), col, BracketType(e.intAttribute("type", -1)));
    4081            0 :         EditStaffBrackets::setBracketSpan(ctx.score(), s->idx(), col, e.intAttribute("span", 0));
    4082            0 :         EditStaffBrackets::setBracketVisible(ctx.score(), s->idx(), col, static_cast<bool>(e.intAttribute("visible", 1)));
    4083            0 :         BracketItem* bi = ctx.score()->brackets(s->idx()).at(col);
    4084            0 :         if (color.isValid()) {
    4085            0 :             bi->setColor(color);
    4086              :         }
    4087            0 :         e.readNext();
    4088          406 :     } else if (tag == "BracketItem") {
    4089           38 :         BracketItem* b = Factory::createBracketItem(s);
    4090           38 :         b->setStartStaffIdx(s->idx());
    4091           38 :         read(b, e, ctx);
    4092           38 :         EditStaffBrackets::insertBracket(ctx.score(), s->idx(), b);
    4093          368 :     } else if (tag == "barLineSpan") {
    4094           29 :         const int barLineSpan = e.readInt();
    4095           29 :         if (barLineSpan < 0) {
    4096            0 :             LOGW() << "barLineSpan is negative: " << barLineSpan;
    4097            0 :             s->setBarLineSpan(false);
    4098           29 :         } else if (barLineSpan > 1) {
    4099            0 :             LOGW() << "barLineSpan is > 1: " << barLineSpan;
    4100            0 :             s->setBarLineSpan(true);
    4101              :         } else {
    4102           29 :             s->setBarLineSpan(static_cast<bool>(barLineSpan));
    4103              :         }
    4104          339 :     } else if (tag == "barLineSpanFrom") {
    4105            0 :         s->setBarLineFrom(e.readInt());
    4106          339 :     } else if (tag == "barLineSpanTo") {
    4107            0 :         s->setBarLineTo(e.readInt());
    4108          339 :     } else if (tag == "distOffset") {
    4109            0 :         s->setUserDist(Spatium(e.readDouble()));
    4110          339 :     } else if (tag == "mag") {
    4111              :         /*_userMag =*/
    4112            0 :         e.readDouble(0.1, 10.0);
    4113          339 :     } else if (tag == "eid") {
    4114          269 :         readItemEID(s, e, ctx);
    4115           70 :     } else if (tag == "linkedTo") {
    4116           70 :         readItemLink(s, e, ctx);
    4117            0 :     } else if (tag == "color") {
    4118            0 :         s->staffType(Fraction(0, 1))->setColor(e.readColor());
    4119            0 :     } else if (tag == "transposeDiatonic") {
    4120            0 :         ctx.setTransposeDiatonic(static_cast<int8_t>(e.readInt()));
    4121            0 :     } else if (tag == "transposeChromatic") {
    4122            0 :         ctx.setTransposeChromatic(static_cast<int8_t>(e.readInt()));
    4123            0 :     } else if (tag == "playbackVoice1") {
    4124            0 :         s->setPlaybackVoice(0, e.readInt());
    4125            0 :     } else if (tag == "playbackVoice2") {
    4126            0 :         s->setPlaybackVoice(1, e.readInt());
    4127            0 :     } else if (tag == "playbackVoice3") {
    4128            0 :         s->setPlaybackVoice(2, e.readInt());
    4129            0 :     } else if (tag == "playbackVoice4") {
    4130            0 :         s->setPlaybackVoice(3, e.readInt());
    4131            0 :     } else if (TRead::readProperty(s, tag, e, ctx, Pid::SHOW_MEASURE_NUMBERS)) {
    4132              :     } else {
    4133            0 :         return false;
    4134              :     }
    4135          807 :     return true;
    4136              : }
    4137              : 
    4138           38 : void TRead::read(BracketItem* b, XmlReader& xml, ReadContext& ctx)
    4139              : {
    4140          152 :     while (xml.readNextStartElement()) {
    4141          114 :         const AsciiStringView& tag = xml.name();
    4142          114 :         if (tag == "type") {
    4143           38 :             b->setBracketType(TConv::fromXml(xml.readAsciiText(), BracketType::NORMAL));
    4144           76 :         } else if (readProperty(b, tag, xml, ctx, Pid::BRACKET_SPAN)) {
    4145           38 :         } else if (tag == "level") {
    4146           38 :             b->setColumn(xml.readInt());
    4147            0 :         } else if (readProperty(b, tag, xml, ctx, Pid::VISIBLE)) {
    4148            0 :         } else if (readProperty(b, tag, xml, ctx, Pid::GROUP_BRACKET_SHOW_TEXT)) {
    4149            0 :         } else if (readProperty(b, tag, xml, ctx, Pid::GROUP_BRACKET_SHOW_BRACKET)) {
    4150            0 :         } else if (tag == "StaffLabel") {
    4151            0 :             StaffLabel& label = b->label();
    4152            0 :             readStaffLabel(label, xml);
    4153              :         } else {
    4154            0 :             xml.unknown();
    4155              :         }
    4156              :     }
    4157           38 : }
    4158              : 
    4159         2323 : String TRead::readLegacyStaffName(XmlReader& xml)
    4160              : {
    4161         2323 :     String name = lineBreakFromTag(xml.readXml());
    4162         2323 :     if (name.startsWith(u"<html>")) {
    4163              :         // compatibility to old html implementation:
    4164            0 :         name = HtmlParser::parse(name);
    4165              :     }
    4166         2323 :     return name;
    4167            0 : }
    4168              : 
    4169            0 : void TRead::readStaffLabel(StaffLabel& item, XmlReader& xml)
    4170              : {
    4171            0 :     while (xml.readNextStartElement()) {
    4172            0 :         if (!readProperties(item, xml)) {
    4173            0 :             xml.unknown();
    4174              :         }
    4175              :     }
    4176            0 : }
    4177              : 
    4178          535 : bool TRead::readProperties(StaffLabel& item, XmlReader& xml)
    4179              : {
    4180          535 :     AsciiStringView tag = xml.name();
    4181              : 
    4182          535 :     if (tag == "longName") {
    4183          257 :         item.setLongName(lineBreakFromTag(xml.readXml()));
    4184          278 :     } else if (tag == "shortName") {
    4185          255 :         item.setShortName(lineBreakFromTag(xml.readXml()));
    4186              :     } else {
    4187           23 :         return false;
    4188              :     }
    4189              : 
    4190          512 :     return true;
    4191              : }
    4192              : 
    4193          257 : void TRead::readInstrumentLabel(InstrumentLabel& item, XmlReader& xml)
    4194              : {
    4195         1049 :     while (xml.readNextStartElement()) {
    4196          535 :         if (!readProperties(item, xml)) {
    4197            0 :             xml.unknown();
    4198              :         }
    4199              :     }
    4200          257 : }
    4201              : 
    4202          535 : bool TRead::readProperties(InstrumentLabel& item, XmlReader& xml)
    4203              : {
    4204          535 :     AsciiStringView tag = xml.name();
    4205              : 
    4206          535 :     if (readProperties(static_cast<StaffLabel&>(item), xml)) {
    4207           23 :     } else if (tag == "transposition") {
    4208            0 :         item.setTransposition(lineBreakFromTag(xml.readXml()));
    4209           23 :     } else if (tag == "showTranspositionLong") {
    4210            0 :         item.setShowTranspositionLong(xml.readBool());
    4211           23 :     } else if (tag == "showTranspositionShort") {
    4212            0 :         item.setShowTranspositionShort(xml.readBool());
    4213           23 :     } else if (tag == "number") {
    4214           20 :         item.setNumber(xml.readInt());
    4215            3 :     } else if (tag == "showNumberLong") {
    4216            1 :         item.setShowNumberLong(xml.readBool());
    4217            2 :     } else if (tag == "showNumberShort") {
    4218            1 :         item.setShowNumberShort(xml.readBool());
    4219            1 :     } else if (tag == "useCustomName") {
    4220            0 :         item.setUseCustomName(xml.readBool());
    4221            1 :     } else if (tag == "customNameLong") {
    4222            0 :         item.setCustomNameLong(lineBreakFromTag(xml.readXml()));
    4223            1 :     } else if (tag == "customNameShort") {
    4224            0 :         item.setCustomNameShort(lineBreakFromTag(xml.readXml()));
    4225            1 :     } else if (tag == "allowGroupName") {
    4226            1 :         item.setAllowGroupName(xml.readBool());
    4227            0 :     } else if (tag == "customNameLongGroup") {
    4228            0 :         item.setCustomNameLongGroup(lineBreakFromTag(xml.readXml()));
    4229            0 :     } else if (tag == "customNameShortGroup") {
    4230            0 :         item.setCustomNameShortGroup(lineBreakFromTag(xml.readXml()));
    4231            0 :     } else if (tag == "useCustomGroupName") {
    4232            0 :         item.setUseCustomGroupName(xml.readBool());
    4233            0 :     } else if (tag == "customNameLongIndividual") {
    4234            0 :         item.setCustomNameLongIndividual(lineBreakFromTag(xml.readXml()));
    4235            0 :     } else if (tag == "customNameShortIndividual") {
    4236            0 :         item.setCustomNameShortIndividual(lineBreakFromTag(xml.readXml()));
    4237            0 :     } else if (tag == "useCustomIndividualName") {
    4238            0 :         item.setUseCustomIndividualName(xml.readBool());
    4239              :     } else {
    4240            0 :         return false;
    4241              :     }
    4242              : 
    4243          535 :     return true;
    4244              : }
    4245              : 
    4246            0 : void TRead::read(Stem* s, XmlReader& e, ReadContext& ctx)
    4247              : {
    4248            0 :     while (e.readNextStartElement()) {
    4249            0 :         if (!TRead::readProperties(s, e, ctx)) {
    4250            0 :             e.unknown();
    4251              :         }
    4252              :     }
    4253            0 : }
    4254              : 
    4255            0 : bool TRead::readProperties(Stem* s, XmlReader& e, ReadContext& ctx)
    4256              : {
    4257            0 :     const AsciiStringView tag(e.name());
    4258              : 
    4259            0 :     if (TRead::readProperty(s, tag, e, ctx, Pid::USER_LEN)) {
    4260            0 :     } else if (TRead::readStyledProperty(s, tag, e, ctx)) {
    4261            0 :     } else if (readItemProperties(s, e, ctx)) {
    4262              :     } else {
    4263            0 :         return false;
    4264              :     }
    4265            0 :     return true;
    4266              : }
    4267              : 
    4268            0 : void TRead::read(StemSlash* s, XmlReader& e, ReadContext& ctx)
    4269              : {
    4270            0 :     while (e.readNextStartElement()) {
    4271            0 :         if (!readItemProperties(s, e, ctx)) {
    4272            0 :             e.unknown();
    4273              :         }
    4274              :     }
    4275            0 : }
    4276              : 
    4277            2 : void TRead::read(StringData* item, XmlReader& e)
    4278              : {
    4279            2 :     item->stringList().clear();
    4280           16 :     while (e.readNextStartElement()) {
    4281           14 :         const AsciiStringView tag(e.name());
    4282           14 :         if (tag == "frets") {
    4283            2 :             item->setFrets(e.readInt());
    4284           12 :         } else if (tag == "string") {
    4285           12 :             instrString strg;
    4286           12 :             strg.open  = e.intAttribute("open", 0);
    4287           12 :             strg.useFlat = e.intAttribute("useFlat", 0);
    4288           12 :             strg.pitch = e.readInt();
    4289           12 :             item->stringList().push_back(strg);
    4290              :         } else {
    4291            0 :             e.unknown();
    4292              :         }
    4293              :     }
    4294            2 :     if (item->isFiveStringBanjo()) {
    4295            0 :         item->configBanjo5thString();
    4296              :     }
    4297            2 : }
    4298              : 
    4299            0 : void TRead::read(StringTunings* s, XmlReader& xml, ReadContext& ctx)
    4300              : {
    4301            0 :     while (xml.readNextStartElement()) {
    4302            0 :         const AsciiStringView tag(xml.name());
    4303              : 
    4304            0 :         if (tag == "preset") {
    4305            0 :             s->setPreset(xml.readText());
    4306            0 :         } else if (tag == "StringData") {
    4307            0 :             StringData sd;
    4308            0 :             read(&sd, xml);
    4309            0 :             s->setStringData(sd);
    4310            0 :         } else if (tag == "visibleStrings") {
    4311            0 :             s->setVisibleStrings(TConv::fromXml(xml.readText(), std::vector<string_idx_t>()));
    4312            0 :         } else if (!readProperties(static_cast<StaffTextBase*>(s), xml, ctx)) {
    4313            0 :             xml.unknown();
    4314              :         }
    4315              :     }
    4316            0 : }
    4317              : 
    4318            0 : void TRead::read(System* s, XmlReader& e, ReadContext& ctx)
    4319              : {
    4320            0 :     while (e.readNextStartElement()) {
    4321            0 :         const AsciiStringView tag(e.name());
    4322            0 :         if (tag == "SystemDivider") {
    4323            0 :             SystemDivider* sd = new SystemDivider(s);
    4324            0 :             TRead::read(sd, e, ctx);
    4325            0 :             s->add(sd);
    4326              :         } else {
    4327            0 :             e.unknown();
    4328              :         }
    4329              :     }
    4330            0 : }
    4331              : 
    4332          384 : void TRead::read(Text* t, XmlReader& e, ReadContext& ctx)
    4333              : {
    4334         1490 :     while (e.readNextStartElement()) {
    4335         1106 :         const AsciiStringView tag(e.name());
    4336         1106 :         if (tag == "style") {
    4337          384 :             TextStyleType s = TConv::fromXml(e.readAsciiText(), TextStyleType::DEFAULT);
    4338          384 :             if (TextStyleType::TUPLET == s) {  // ugly hack for compatibility
    4339          120 :                 continue;
    4340              :             }
    4341          264 :             t->initTextStyleType(s);
    4342          722 :         } else if (!readProperties(toTextBase(t), e, ctx)) {
    4343            0 :             e.unknown();
    4344              :         }
    4345              :     }
    4346          384 : }
    4347              : 
    4348           37 : void TRead::read(TextLine* l, XmlReader& e, ReadContext& ctx)
    4349              : {
    4350           37 :     bool system =  e.intAttribute("system", 0) == 1;
    4351           37 :     l->setSystemFlag(system);
    4352           37 :     l->initStyle();
    4353           37 :     TRead::read(toTextLineBase(l), e, ctx);
    4354           37 : }
    4355              : 
    4356          129 : void TRead::read(TextLineBase* b, XmlReader& e, ReadContext& ctx)
    4357              : {
    4358          129 :     b->eraseSpannerSegments();
    4359              : 
    4360          994 :     while (e.readNextStartElement()) {
    4361          736 :         if (!readProperties(b, e, ctx)) {
    4362            0 :             e.unknown();
    4363              :         }
    4364              :     }
    4365          129 :     if (ctx.mscVersion() < 470) {
    4366            0 :         compat::CompatUtils::setTextLineTextPositionFromAlign(b);
    4367              :     }
    4368          129 : }
    4369              : 
    4370           32 : void TRead::read(Tie* t, XmlReader& xml, ReadContext& ctx)
    4371              : {
    4372          160 :     while (xml.readNextStartElement()) {
    4373          128 :         AsciiStringView tag = xml.name();
    4374          128 :         if (TRead::readProperty(t, tag, xml, ctx, Pid::TIE_PLACEMENT)) {
    4375          128 :         } else if (!readProperties(toSlurTie(t), xml, ctx)) {
    4376            0 :             xml.unknown();
    4377              :         }
    4378              :     }
    4379           32 : }
    4380              : 
    4381          381 : void TRead::read(TimeSig* s, XmlReader& e, ReadContext& ctx)
    4382              : {
    4383          381 :     int n=0, z1=0, z2=0, z3=0, z4=0;
    4384          381 :     bool old = false;
    4385              : 
    4386          381 :     TimeSigType timeSigType = TimeSigType::NORMAL;
    4387          381 :     Fraction sig;
    4388          381 :     Fraction stretch(1, 1);
    4389          381 :     String numeratorString;
    4390          381 :     String denominatorString;
    4391              : 
    4392         1475 :     while (e.readNextStartElement()) {
    4393         1094 :         const AsciiStringView tag(e.name());
    4394              : 
    4395         1094 :         if (tag == "den") {
    4396            0 :             old = true;
    4397            0 :             n = e.readInt();
    4398         1094 :         } else if (tag == "nom1") {
    4399            0 :             old = true;
    4400            0 :             z1 = e.readInt();
    4401         1094 :         } else if (tag == "nom2") {
    4402            0 :             old = true;
    4403            0 :             z2 = e.readInt();
    4404         1094 :         } else if (tag == "nom3") {
    4405            0 :             old = true;
    4406            0 :             z3 = e.readInt();
    4407         1094 :         } else if (tag == "nom4") {
    4408            0 :             old = true;
    4409            0 :             z4 = e.readInt();
    4410         1094 :         } else if (tag == "subtype") {
    4411            0 :             timeSigType = TimeSigType(e.readInt());
    4412         1094 :         } else if (tag == "showCourtesySig") {
    4413            0 :             s->setShowCourtesySig(e.readInt());
    4414         1094 :         } else if (tag == "sigN") {
    4415          381 :             sig.setNumerator(e.readInt());
    4416          713 :         } else if (tag == "sigD") {
    4417          381 :             sig.setDenominator(e.readInt());
    4418          332 :         } else if (tag == "stretchN") {
    4419            1 :             stretch.setNumerator(e.readInt());
    4420          331 :         } else if (tag == "stretchD") {
    4421            1 :             stretch.setDenominator(e.readInt());
    4422          330 :         } else if (tag == "textN") {
    4423            0 :             numeratorString = e.readText();
    4424          330 :         } else if (tag == "textD") {
    4425            0 :             denominatorString = e.readText();
    4426          330 :         } else if (tag == "Groups") {
    4427            0 :             Groups groups;
    4428            0 :             TRead::read(&groups, e, ctx);
    4429            0 :             s->setGroups(groups);
    4430          330 :         } else if (tag == "isCourtesy") {
    4431            0 :             s->setIsCourtesy(e.readBool());
    4432          330 :         } else if (TRead::readStyledProperty(s, tag, e, ctx)) {
    4433          330 :         } else if (!readItemProperties(s, e, ctx)) {
    4434            0 :             e.unknown();
    4435              :         }
    4436              :     }
    4437          381 :     if (old) {
    4438            0 :         sig.set(z1 + z2 + z3 + z4, n);
    4439              :     }
    4440          381 :     stretch.reduce();
    4441              : 
    4442          381 :     s->setSig(sig, timeSigType);
    4443          381 :     s->setStretch(stretch);
    4444          381 :     s->setNumeratorString(numeratorString);
    4445          381 :     s->setDenominatorString(denominatorString);
    4446          381 : }
    4447              : 
    4448            3 : void TRead::read(TremoloTwoChord* t, XmlReader& xml, ReadContext& ctx)
    4449              : {
    4450            3 :     compat::TremoloCompat tc { parentOrDummy(t->chord(), ctx.dummy()) };
    4451            3 :     tc.two = t;
    4452            3 :     read(&tc, xml, ctx);
    4453            3 : }
    4454              : 
    4455           18 : void TRead::read(TremoloSingleChord* t, XmlReader& xml, ReadContext& ctx)
    4456              : {
    4457           18 :     compat::TremoloCompat tc { parentOrDummy(t->chord(), ctx.dummy()) };
    4458           18 :     tc.single = t;
    4459           18 :     read(&tc, xml, ctx);
    4460           18 : }
    4461              : 
    4462           21 : void TRead::read(compat::TremoloCompat* tc, XmlReader& e, ReadContext& ctx)
    4463              : {
    4464           88 :     auto item = [](compat::TremoloCompat* tc) -> EngravingItem* {
    4465           88 :         if (tc->two) {
    4466           18 :             return tc->two;
    4467              :         }
    4468           70 :         return tc->single;
    4469              :     };
    4470              : 
    4471           21 :     const Chord* chord = tc->parent.as<Chord>();
    4472           21 :     const track_idx_t track = chord ? chord->track() : 0;
    4473              : 
    4474           86 :     while (e.readNextStartElement()) {
    4475           65 :         const AsciiStringView tag(e.name());
    4476           65 :         if (tag == "subtype") {
    4477           21 :             TremoloType type = TConv::fromXml(e.readAsciiText(), TremoloType::INVALID_TREMOLO);
    4478           21 :             if (isTremoloTwoChord(type)) {
    4479            3 :                 if (!tc->two) {
    4480            0 :                     tc->two = Factory::createTremoloTwoChord(tc->parent);
    4481            0 :                     tc->two->setTrack(track);
    4482              :                 }
    4483            3 :                 tc->two->setTremoloType(type);
    4484              :             } else {
    4485           18 :                 if (!tc->single) {
    4486            0 :                     tc->single = Factory::createTremoloSingleChord(tc->parent);
    4487            0 :                     tc->single->setTrack(track);
    4488              :                 }
    4489           18 :                 tc->single->setTremoloType(type);
    4490              :             }
    4491              :         }
    4492              :         // Style needs special handling other than readStyledProperty()
    4493              :         // to avoid calling customStyleApplicable() in setProperty(),
    4494              :         // which cannot be called now because durationType() isn't defined yet.
    4495           44 :         else if (tag == "strokeStyle") {
    4496            0 :             if (tc->two) {
    4497            0 :                 tc->two->setTremoloStyle(TremoloStyle(e.readInt()));
    4498            0 :                 tc->two->setPropertyFlags(Pid::TREMOLO_STYLE, PropertyFlags::UNSTYLED);
    4499              :             } else {
    4500            0 :                 UNREACHABLE;
    4501              :                 e.skipCurrentElement();
    4502              :             }
    4503           44 :         } else if (tag == "Fragment") {
    4504            0 :             if (tc->two) {
    4505            0 :                 BeamFragment f = BeamFragment();
    4506            0 :                 int idx = tc->two->directionIdx();
    4507            0 :                 tc->two->setUserModified(true);
    4508            0 :                 double _spatium = tc->two->spatium();
    4509            0 :                 while (e.readNextStartElement()) {
    4510            0 :                     const AsciiStringView tag1(e.name());
    4511            0 :                     if (tag1 == "y1") {
    4512            0 :                         f.py1[idx] = e.readDouble() * _spatium;
    4513            0 :                     } else if (tag1 == "y2") {
    4514            0 :                         f.py2[idx] = e.readDouble() * _spatium;
    4515              :                     } else {
    4516            0 :                         e.unknown();
    4517              :                     }
    4518              :                 }
    4519            0 :                 tc->two->setBeamFragment(f);
    4520              :             } else {
    4521            0 :                 UNREACHABLE;
    4522              :                 e.skipCurrentElement();
    4523              :             }
    4524           44 :         } else if (tag == "play") {
    4525            0 :             if (tc->two) {
    4526            0 :                 tc->two->setPlayTremolo(e.readBool());
    4527            0 :             } else if (tc->single) {
    4528            0 :                 tc->single->setPlayTremolo(e.readBool());
    4529              :             } else {
    4530            0 :                 UNREACHABLE;
    4531              :             }
    4532           44 :         } else if (TRead::readStyledProperty(item(tc), tag, e, ctx)) {
    4533           44 :         } else if (!readItemProperties(item(tc), e, ctx)) {
    4534            6 :             e.unknown();
    4535              :         }
    4536              :     }
    4537           21 : }
    4538              : 
    4539              : static constexpr std::array<Pid, 18> TextBasePropertyId { {
    4540              :     Pid::TEXT_STYLE,
    4541              :     Pid::FONT_FACE,
    4542              :     Pid::FONT_SIZE,
    4543              :     Pid::TEXT_LINE_SPACING,
    4544              :     Pid::FONT_STYLE,
    4545              :     Pid::COLOR,
    4546              :     Pid::FRAME_TYPE,
    4547              :     Pid::FRAME_WIDTH,
    4548              :     Pid::FRAME_PADDING,
    4549              :     Pid::FRAME_ROUND,
    4550              :     Pid::FRAME_FG_COLOR,
    4551              :     Pid::FRAME_BG_COLOR,
    4552              :     Pid::ALIGN,
    4553              :     Pid::POSITION,
    4554              : } };
    4555              : 
    4556            0 : bool TRead::readTextProperties(TextBase* t, XmlReader& xml, ReadContext& ctx)
    4557              : {
    4558            0 :     if (t->isStaffTextBase()) {
    4559            0 :         return readProperties(dynamic_cast<StaffTextBase*>(t), xml, ctx);
    4560              :     }
    4561            0 :     return readProperties(t, xml, ctx);
    4562              : }
    4563              : 
    4564         1344 : bool TRead::readProperties(TextBase* t, XmlReader& e, ReadContext& ctx)
    4565              : {
    4566         1344 :     const AsciiStringView tag(e.name());
    4567        25270 :     for (Pid i : TextBasePropertyId) {
    4568        23941 :         if (TRead::readProperty(t, tag, e, ctx, i)) {
    4569           15 :             if (ctx.mscVersion() >= 470 || tag != "align" || t->isMarker() || t->isJump() || t->isHarmony()) {
    4570           15 :                 return true;
    4571              :             }
    4572              : 
    4573            0 :             t->setPosition(t->align().horizontal);
    4574            0 :             if (t->position() != t->propertyDefault(Pid::POSITION).value<AlignH>()) {
    4575            0 :                 t->setPropertyFlags(Pid::POSITION, PropertyFlags::UNSTYLED);
    4576              :             }
    4577            0 :             return true;
    4578              :         }
    4579              :     }
    4580              : 
    4581         1329 :     if (tag == "text") {
    4582          594 :         String str = lineBreakFromTag(e.readXml());
    4583          594 :         t->setXmlText(str);
    4584          594 :         t->checkCustomFormatting(str);
    4585         1329 :     } else if (tag == "bold") {
    4586            0 :         bool val = e.readInt();
    4587            0 :         if (val) {
    4588            0 :             t->setFontStyle(t->fontStyle() + FontStyle::Bold);
    4589              :         } else {
    4590            0 :             t->setFontStyle(t->fontStyle() - FontStyle::Bold);
    4591              :         }
    4592            0 :         if (t->isStyled(Pid::FONT_STYLE)) {
    4593            0 :             t->setPropertyFlags(Pid::FONT_STYLE, PropertyFlags::UNSTYLED);
    4594              :         }
    4595          735 :     } else if (tag == "italic") {
    4596            0 :         bool val = e.readInt();
    4597            0 :         if (val) {
    4598            0 :             t->setFontStyle(t->fontStyle() + FontStyle::Italic);
    4599              :         } else {
    4600            0 :             t->setFontStyle(t->fontStyle() - FontStyle::Italic);
    4601              :         }
    4602            0 :         if (t->isStyled(Pid::FONT_STYLE)) {
    4603            0 :             t->setPropertyFlags(Pid::FONT_STYLE, PropertyFlags::UNSTYLED);
    4604              :         }
    4605          735 :     } else if (tag == "underline") {
    4606            0 :         bool val = e.readInt();
    4607            0 :         if (val) {
    4608            0 :             t->setFontStyle(t->fontStyle() + FontStyle::Underline);
    4609              :         } else {
    4610            0 :             t->setFontStyle(t->fontStyle() - FontStyle::Underline);
    4611              :         }
    4612            0 :         if (t->isStyled(Pid::FONT_STYLE)) {
    4613            0 :             t->setPropertyFlags(Pid::FONT_STYLE, PropertyFlags::UNSTYLED);
    4614              :         }
    4615          735 :     } else if (tag == "strike") {
    4616            0 :         bool val = e.readInt();
    4617            0 :         if (val) {
    4618            0 :             t->setFontStyle(t->fontStyle() + FontStyle::Strike);
    4619              :         } else {
    4620            0 :             t->setFontStyle(t->fontStyle() - FontStyle::Strike);
    4621              :         }
    4622            0 :         if (t->isStyled(Pid::FONT_STYLE)) {
    4623            0 :             t->setPropertyFlags(Pid::FONT_STYLE, PropertyFlags::UNSTYLED);
    4624              :         }
    4625          735 :     } else if (TRead::readProperty(t, tag, e, ctx, Pid::TEXT_LINKED_TO_MASTER)) {
    4626          735 :     } else if (readProperty(t, tag, e, ctx, Pid::VOICE_ASSIGNMENT)) {
    4627          733 :     } else if (readProperty(t, tag, e, ctx, Pid::DIRECTION)) {
    4628          723 :     } else if (readProperty(t, tag, e, ctx, Pid::CENTER_BETWEEN_STAVES)) {
    4629          722 :     } else if (readProperty(t, tag, e, ctx, Pid::MUSIC_SYMBOL_SIZE)) {
    4630          722 :     } else if (readProperty(t, tag, e, ctx, Pid::MUSICAL_SYMBOLS_SCALE)) {
    4631          720 :     } else if (!readItemProperties(t, e, ctx)) {
    4632            0 :         return false;
    4633              :     }
    4634         1329 :     return true;
    4635              : }
    4636              : 
    4637         2321 : bool TRead::readProperties(TextLineBase* b, XmlReader& e, ReadContext& ctx)
    4638              : {
    4639         2321 :     const AsciiStringView tag(e.name());
    4640        91432 :     for (Pid i : TextLineBase::textLineBasePropertyIds()) {
    4641        89772 :         if (TRead::readProperty(b, tag, e, ctx, i)) {
    4642          661 :             return true;
    4643              :         }
    4644              :     }
    4645         1660 :     return readProperties(static_cast<SLine*>(b), e, ctx);
    4646              : }
    4647              : 
    4648            2 : void TRead::read(Trill* t, XmlReader& e, ReadContext& ctx)
    4649              : {
    4650            2 :     t->eraseSpannerSegments();
    4651              : 
    4652           16 :     while (e.readNextStartElement()) {
    4653           14 :         const AsciiStringView tag(e.name());
    4654           14 :         if (tag == "subtype") {
    4655            2 :             t->setTrillType(TConv::fromXml(e.readAsciiText(), TrillType::TRILL_LINE));
    4656           12 :         } else if (tag == "Ornament") {
    4657            1 :             Ornament* ornament = t->ornament();
    4658            1 :             if (!ornament) {
    4659            0 :                 ornament = Factory::createOrnament(toChordRest(t->ownershipParent()));
    4660            0 :                 t->setOrnament(ornament);
    4661              :             }
    4662            1 :             ornament->setSymId(Ornament::fromTrillType(t->trillType()));
    4663            1 :             TRead::read(ornament, e, ctx);
    4664            1 :             ornament->setTrack(t->track());
    4665           11 :         } else if (tag == "Accidental") {
    4666            0 :             Accidental* accidental = Factory::createAccidental(t);
    4667            0 :             TRead::read(accidental, e, ctx);
    4668            0 :             t->setAccidental(accidental);
    4669            0 :             if (t->ornament()) {
    4670            0 :                 t->ornament()->setTrillOldCompatAccidental(accidental);
    4671              :             }
    4672           11 :         } else if (tag == "ornamentStyle") {
    4673            0 :             readProperty(t, e, ctx, Pid::ORNAMENT_STYLE);
    4674           11 :         } else if (!readProperties(static_cast<SLine*>(t), e, ctx)) {
    4675            0 :             e.unknown();
    4676              :         }
    4677              :     }
    4678            2 : }
    4679              : 
    4680            1 : void TRead::read(Vibrato* v, XmlReader& e, ReadContext& ctx)
    4681              : {
    4682            1 :     v->eraseSpannerSegments();
    4683              : 
    4684            7 :     while (e.readNextStartElement()) {
    4685            6 :         const AsciiStringView tag(e.name());
    4686            6 :         if (tag == "subtype") {
    4687            1 :             v->setVibratoType(TConv::fromXml(e.readAsciiText(), VibratoType::GUITAR_VIBRATO));
    4688            5 :         } else if (!readProperties(static_cast<SLine*>(v), e, ctx)) {
    4689            0 :             e.unknown();
    4690              :         }
    4691              :     }
    4692            1 : }
    4693              : 
    4694            7 : void TRead::read(Volta* v, XmlReader& e, ReadContext& ctx)
    4695              : {
    4696            7 :     v->eraseSpannerSegments();
    4697              : 
    4698           53 :     while (e.readNextStartElement()) {
    4699           46 :         const AsciiStringView tag(e.name());
    4700           46 :         if (tag == "endings") {
    4701            7 :             v->setEndings(TConv::fromXml(e.readText(), std::vector<int>()));
    4702           39 :         } else if (!readProperties(v, e, ctx)) {
    4703            0 :             e.unknown();
    4704              :         }
    4705              :     }
    4706            7 :     if (ctx.mscVersion() < 470) {
    4707            0 :         compat::CompatUtils::setTextLineTextPositionFromAlign(v);
    4708              :     }
    4709            7 : }
    4710              : 
    4711           39 : bool TRead::readProperties(Volta* v, XmlReader& e, ReadContext& ctx)
    4712              : {
    4713           39 :     if (!readProperties(toTextLineBase(v), e, ctx)) {
    4714            0 :         return false;
    4715              :     }
    4716              : 
    4717           39 :     return true;
    4718              : }
    4719              : 
    4720            7 : void TRead::readPageLocks(Score* score, XmlReader& e)
    4721              : {
    4722           35 :     while (e.readNextStartElement()) {
    4723           28 :         if (e.name() == "pageLock") {
    4724           28 :             readPageLock(score, e);
    4725              :         } else {
    4726            0 :             e.unknown();
    4727              :         }
    4728              :     }
    4729            7 : }
    4730              : 
    4731            0 : void TRead::readSystemLocks(Score* score, XmlReader& e)
    4732              : {
    4733            0 :     while (e.readNextStartElement()) {
    4734            0 :         if (e.name() == "systemLock") {
    4735            0 :             readSystemLock(score, e);
    4736              :         } else {
    4737            0 :             e.unknown();
    4738              :         }
    4739              :     }
    4740            0 : }
    4741              : 
    4742           28 : void TRead::readPageLock(Score* score, XmlReader& e)
    4743              : {
    4744           28 :     MeasureBase* startMeas = nullptr;
    4745           28 :     MeasureBase* endMeas = nullptr;
    4746           28 :     EIDRegister* eidRegister = score->masterScore()->eidRegister();
    4747              : 
    4748           84 :     while (e.readNextStartElement()) {
    4749           56 :         AsciiStringView tag(e.name());
    4750           56 :         if (tag == "startMeasure") {
    4751           28 :             EID startMeasId = EID::fromStdString(e.readAsciiText());
    4752           28 :             startMeas = toMeasureBase(eidRegister->itemFromEID(startMeasId));
    4753           28 :         } else if (tag == "endMeasure") {
    4754           28 :             EID endMeasId = EID::fromStdString(e.readAsciiText());
    4755           28 :             endMeas = toMeasureBase(eidRegister->itemFromEID(endMeasId));
    4756              :         } else {
    4757            0 :             e.unknown();
    4758              :         }
    4759              :     }
    4760              : 
    4761           28 :     IF_ASSERT_FAILED(startMeas && endMeas) {
    4762            0 :         return;
    4763              :     }
    4764              : 
    4765           28 :     score->addPageLock(new RangeLock(startMeas, endMeas));
    4766              : }
    4767              : 
    4768            0 : void TRead::readSystemLock(Score* score, XmlReader& e)
    4769              : {
    4770            0 :     MeasureBase* startMeas = nullptr;
    4771            0 :     MeasureBase* endMeas = nullptr;
    4772            0 :     EIDRegister* eidRegister = score->masterScore()->eidRegister();
    4773              : 
    4774            0 :     while (e.readNextStartElement()) {
    4775            0 :         AsciiStringView tag(e.name());
    4776            0 :         if (tag == "startMeasure") {
    4777            0 :             EID startMeasId = EID::fromStdString(e.readAsciiText());
    4778            0 :             startMeas = toMeasureBase(eidRegister->itemFromEID(startMeasId));
    4779            0 :         } else if (tag == "endMeasure") {
    4780            0 :             EID endMeasId = EID::fromStdString(e.readAsciiText());
    4781            0 :             endMeas = toMeasureBase(eidRegister->itemFromEID(endMeasId));
    4782              :         } else {
    4783            0 :             e.unknown();
    4784              :         }
    4785              :     }
    4786              : 
    4787            0 :     IF_ASSERT_FAILED(startMeas && endMeas) {
    4788            0 :         return;
    4789              :     }
    4790              : 
    4791            0 :     score->addSystemLock(new RangeLock(startMeas, endMeas));
    4792              : }
    4793              : 
    4794            0 : void TRead::readSystemDividers(Score* score, XmlReader& e, ReadContext& ctx)
    4795              : {
    4796            0 :     while (e.readNextStartElement()) {
    4797            0 :         if (e.name() == "system") {
    4798            0 :             size_t systemIdx = e.intAttribute("idx");
    4799            0 :             while (e.readNextStartElement()) {
    4800            0 :                 if (e.name() == "SystemDivider") {
    4801            0 :                     SystemDivider* divider = new SystemDivider(score->dummy());
    4802            0 :                     read(divider, e, ctx);
    4803            0 :                     score->addSystemDivider(systemIdx, divider);
    4804              :                 } else {
    4805            0 :                     e.unknown();
    4806              :                 }
    4807              :             }
    4808              :         } else {
    4809            0 :             e.unknown();
    4810              :         }
    4811              :     }
    4812            0 : }
        

Generated by: LCOV version 2.0-1