LCOV - code coverage report
Current view: top level - src/engraving/rw/read500 - readcontext.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 81.9 % 144 118
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore-Studio-CLA-applies
       4              :  *
       5              :  * MuseScore Studio
       6              :  * Music Composition & Notation
       7              :  *
       8              :  * Copyright (C) 2026 MuseScore Limited
       9              :  *
      10              :  * This program is free software: you can redistribute it and/or modify
      11              :  * it under the terms of the GNU General Public License version 3 as
      12              :  * published by the Free Software Foundation.
      13              :  *
      14              :  * This program is distributed in the hope that it will be useful,
      15              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17              :  * GNU General Public License for more details.
      18              :  *
      19              :  * You should have received a copy of the GNU General Public License
      20              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      21              :  */
      22              : 
      23              : #include "readcontext.h"
      24              : 
      25              : #include "dom/masterscore.h"
      26              : #include "dom/measure.h"
      27              : #include "dom/note.h"
      28              : #include "dom/score.h"
      29              : 
      30              : #include "log.h"
      31              : 
      32              : using namespace mu::engraving;
      33              : using namespace mu::engraving::read500;
      34              : 
      35          805 : ReadContext::ReadContext(Score* score, bool pasteMode)
      36          805 :     : m_score(score), _pasteMode(pasteMode)
      37              : {
      38          805 : }
      39              : 
      40          805 : ReadContext::~ReadContext()
      41              : {
      42          805 :     IF_ASSERT_FAILED(m_incompleteNoteAnchoredSpanners.empty()) {
      43            0 :         for (auto& [spanner, startEndEIDs] : m_incompleteNoteAnchoredSpanners) {
      44            0 :             delete spanner;
      45              :         }
      46              : 
      47            0 :         m_incompleteNoteAnchoredSpanners.clear();
      48              :     }
      49          805 : }
      50              : 
      51        10813 : Score* ReadContext::score() const
      52              : {
      53        10813 :     return m_score;
      54              : }
      55              : 
      56          136 : void ReadContext::setScore(Score* score)
      57              : {
      58          136 :     m_score = score;
      59          136 : }
      60              : 
      61           19 : const MStyle& ReadContext::style() const
      62              : {
      63           19 :     return score()->style();
      64              : }
      65              : 
      66            0 : std::shared_ptr<IEngravingFontsProvider> ReadContext::engravingFonts() const
      67              : {
      68            0 :     return score()->engravingFonts();
      69              : }
      70              : 
      71            0 : String ReadContext::mscoreVersion() const
      72              : {
      73            0 :     return m_score->mscoreVersion();
      74              : }
      75              : 
      76          502 : int ReadContext::mscVersion() const
      77              : {
      78          502 :     return m_score->mscVersion();
      79              : }
      80              : 
      81            0 : int ReadContext::fileDivision() const
      82              : {
      83            0 :     return m_score->fileDivision();
      84              : }
      85              : 
      86            0 : int ReadContext::fileDivision(int t) const
      87              : {
      88            0 :     return m_score->fileDivision(t);
      89              : }
      90              : 
      91         1657 : double ReadContext::spatium() const
      92              : {
      93         1657 :     return m_score->style().spatium();
      94              : }
      95              : 
      96            0 : void ReadContext::setSpatium(double v)
      97              : {
      98            0 :     m_score->style().set(Sid::spatium, v);
      99            0 : }
     100              : 
     101         3673 : DummyParent* ReadContext::dummy() const
     102              : {
     103         3673 :     return m_score->dummy();
     104              : }
     105              : 
     106         6519 : Staff* ReadContext::staff(staff_idx_t n)
     107              : {
     108         6519 :     return m_score->staff(n);
     109              : }
     110              : 
     111         6506 : bool ReadContext::isSameScore(const EngravingObject* obj) const
     112              : {
     113         6506 :     return obj->score() == m_score;
     114              : }
     115              : 
     116            2 : Fraction ReadContext::rtick() const
     117              : {
     118            2 :     return _curMeasure ? _tick - _curMeasure->tick() : _tick;
     119              : }
     120              : 
     121        13563 : void ReadContext::setTick(const Fraction& f)
     122              : {
     123        13563 :     _tick = f.reduced();
     124        13563 :     _intTick = _tick.ticks();
     125        13563 : }
     126              : 
     127         9518 : void ReadContext::incTick(const Fraction& f)
     128              : {
     129         9518 :     _tick += f;
     130         9518 :     _tick.reduce();
     131         9518 :     _intTick += f.ticks();
     132         9518 : }
     133              : 
     134          132 : Location ReadContext::location(bool forceAbsFrac) const
     135              : {
     136          132 :     Location l = Location::absolute();
     137          132 :     fillLocation(l, forceAbsFrac);
     138          132 :     return l;
     139              : }
     140              : 
     141              : //---------------------------------------------------------
     142              : //   fillLocation
     143              : //    fills location fields which have default values with
     144              : //    values relevant for the current reader's position.
     145              : //    When in paste mode (or forceAbsFrac is true) absolute
     146              : //    fraction values are used and measure number is set to
     147              : //    zero.
     148              : //---------------------------------------------------------
     149              : 
     150          132 : void ReadContext::fillLocation(Location& l, bool forceAbsFrac) const
     151              : {
     152          132 :     constexpr Location defaults = Location::absolute();
     153          132 :     const bool absFrac = (pasteMode() || forceAbsFrac);
     154          132 :     if (l.track() == defaults.track()) {
     155          132 :         l.setTrack(static_cast<int>(track()));
     156              :     }
     157          132 :     if (l.frac() == defaults.frac()) {
     158          132 :         l.setFrac(absFrac ? tick() : rtick());
     159              :     }
     160          132 :     if (l.measure() == defaults.measure()) {
     161          132 :         l.setMeasure(absFrac ? 0 : currentMeasureIndex());
     162              :     }
     163          132 : }
     164              : 
     165              : //---------------------------------------------------------
     166              : //   setLocation
     167              : //    sets a new reading location, taking into account its
     168              : //    type (absolute or relative).
     169              : //---------------------------------------------------------
     170              : 
     171          221 : void ReadContext::setLocation(const Location& l)
     172              : {
     173          221 :     if (l.isRelative()) {
     174          132 :         Location newLoc = l;
     175          132 :         newLoc.toAbsolute(location());
     176          132 :         int intTicks = l.frac().ticks();
     177          132 :         if (_tick == Fraction::fromTicks(_intTick + intTicks)) {
     178           43 :             _intTick += intTicks;
     179           43 :             setTrack(newLoc.track() - _trackOffset);
     180           43 :             return;
     181              :         }
     182           89 :         setLocation(newLoc); // recursion
     183           89 :         return;
     184              :     }
     185           89 :     setTrack(l.track() - _trackOffset);
     186           89 :     setTick(l.frac() - _tickOffset);
     187           89 :     if (!pasteMode()) {
     188            2 :         assert(l.measure() == currentMeasureIndex());
     189            2 :         incTick(currentMeasure()->tick());
     190              :     }
     191              : }
     192              : 
     193          376 : void ReadContext::addPartAudioSettingCompat(PartAudioSettingsCompat partAudioSetting)
     194              : {
     195          376 :     if (_settingsCompat.audioSettings.count(partAudioSetting.instrumentId.partId) == 0) {
     196          292 :         _settingsCompat.audioSettings.insert({ partAudioSetting.instrumentId.partId, partAudioSetting });
     197              :     }
     198          376 : }
     199              : 
     200           10 : void ReadContext::addMMRestEndMeasureEID(Measure* mmrest, EID lastMeasureEID)
     201              : {
     202           10 :     DO_ASSERT(lastMeasureEID.isValid());
     203           10 :     m_mmRestEndMeasures.emplace(mmrest, lastMeasureEID);
     204           10 : }
     205              : 
     206          238 : void ReadContext::setMMRestEndMeasures()
     207              : {
     208          238 :     EIDRegister* eidRegister = score()->masterScore()->eidRegister();
     209          248 :     for (auto& [mmrest, lastMeasureEID] : m_mmRestEndMeasures) {
     210           10 :         EngravingObject* linkedElement = eidRegister->itemFromEID(lastMeasureEID);
     211           10 :         IF_ASSERT_FAILED(linkedElement && linkedElement->isMeasure()) {
     212            0 :             LOGE() << "No valid end measure found for MMRest at " << mmrest->tick().toString();
     213            0 :             continue;
     214              :         }
     215              : 
     216           10 :         Measure* lastMeasure = toMeasure(linkedElement);
     217           10 :         MeasureBase* nextMB = lastMeasure->next();
     218           10 :         mmrest->setNext(nextMB);
     219              :     }
     220          238 : }
     221              : 
     222         1909 : void ReadContext::registerPastedEID(const EID& clipboardEid, const EID& fileEid)
     223              : {
     224         1909 :     m_pastedEIDs.emplace(clipboardEid, fileEid);
     225         1909 : }
     226              : 
     227           73 : EID ReadContext::resolvePastedEID(const EID& clipboardEid) const
     228              : {
     229           73 :     if (!_pasteMode) {
     230            0 :         return clipboardEid;
     231              :     }
     232              : 
     233           73 :     auto it = m_pastedEIDs.find(clipboardEid);
     234           73 :     IF_ASSERT_FAILED(it != m_pastedEIDs.end()) {
     235            0 :         return clipboardEid;
     236              :     }
     237              : 
     238           73 :     return it->second;
     239              : }
     240              : 
     241           41 : void ReadContext::addNoteAnchoredSpannerStartEl(Spanner* spanner, EID startElementEID)
     242              : {
     243           41 :     auto it = m_incompleteNoteAnchoredSpanners.find(spanner);
     244           41 :     if (it != m_incompleteNoteAnchoredSpanners.end()) {
     245            0 :         it->second.first = startElementEID;
     246              :     } else {
     247           41 :         m_incompleteNoteAnchoredSpanners.emplace(spanner, std::make_pair(startElementEID, EID::invalid()));
     248              :     }
     249           41 : }
     250              : 
     251           41 : void ReadContext::addNoteAnchoredSpannerEndEl(Spanner* spanner, EID endElementEID)
     252              : {
     253           41 :     auto it = m_incompleteNoteAnchoredSpanners.find(spanner);
     254           41 :     if (it != m_incompleteNoteAnchoredSpanners.end()) {
     255           41 :         it->second.second = endElementEID;
     256              :     } else {
     257            0 :         m_incompleteNoteAnchoredSpanners.emplace(spanner, std::make_pair(EID::invalid(), endElementEID));
     258              :     }
     259           41 : }
     260              : 
     261          280 : void ReadContext::connectNoteAnchoredSpanners()
     262              : {
     263          280 :     EIDRegister* eidRegister = score()->masterScore()->eidRegister();
     264          321 :     for (auto& [spanner, startEndEIDs] : m_incompleteNoteAnchoredSpanners) {
     265           41 :         EID startElementEID = startEndEIDs.first;
     266           41 :         EID endElementEID = startEndEIDs.second;
     267           41 :         EngravingItem* startElement = toEngravingItem(eidRegister->itemFromEID(startElementEID));
     268           41 :         EngravingItem* endElement = toEngravingItem(eidRegister->itemFromEID(endElementEID));
     269           41 :         IF_ASSERT_FAILED(startElement && startElement->isNote()) {
     270            0 :             LOGD() << "Could not find note element for " << spanner->typeName();
     271            0 :             delete spanner;
     272            0 :             continue;
     273              :         }
     274           41 :         IF_ASSERT_FAILED(endElement && endElement->isNote()) {
     275            0 :             LOGD() << "Could not find end note for " << spanner->typeName();
     276            0 :             delete spanner;
     277            0 :             continue;
     278              :         }
     279              : 
     280           41 :         Note* startNote = toNote(startElement);
     281           41 :         Note* endNote = toNote(endElement);
     282           41 :         spanner->setNoteSpan(startNote, endNote);
     283              : 
     284           41 :         if (spanner->isTie()) {
     285           32 :             Tie* tie = toTie(spanner);
     286           32 :             startNote->setTieFor(tie);
     287           32 :             endNote->setTieBack(tie);
     288              :         } else {
     289            9 :             score()->addElement(spanner);
     290              :         }
     291              :     }
     292          280 :     m_incompleteNoteAnchoredSpanners.clear();
     293          280 : }
        

Generated by: LCOV version 2.0-1