LCOV - code coverage report
Current view: top level - src/engraving/rw/read460 - tread.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 46.8 % 3278 1534
Test Date: 2026-11-05 04:07:02

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

Generated by: LCOV version 2.0-1