LCOV - code coverage report
Current view: top level - src/engraving/dom - linkedobjects.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 69.8 % 43 30
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              : #include "linkedobjects.h"
      23              : 
      24              : #include "masterscore.h"
      25              : #include "measure.h"
      26              : #include "score.h"
      27              : #include "staff.h"
      28              : 
      29              : #include "log.h"
      30              : 
      31              : using namespace mu::engraving;
      32              : 
      33        10316 : bool LinkedObjects::contains(const EngravingObject* o) const
      34              : {
      35        10316 :     return std::find(this->begin(), this->end(), o) != this->end();
      36              : }
      37              : 
      38              : //---------------------------------------------------------
      39              : //   mainElement
      40              : //    Returns "main" linked element which is expected to
      41              : //    be written to the file prior to others.
      42              : //---------------------------------------------------------
      43              : 
      44        16926 : EngravingObject* LinkedObjects::mainElement()
      45              : {
      46        16926 :     if (empty()) {
      47            0 :         return nullptr;
      48              :     }
      49        16926 :     MasterScore* ms = front()->score()->masterScore();
      50        16926 :     const bool elements = front()->isEngravingItem();
      51        16926 :     const bool staves = front()->isStaff();
      52        33852 :     return *std::min_element(begin(), end(), [ms, elements, staves](EngravingObject* s1, EngravingObject* s2) {
      53        16832 :         if (s1->score() == ms && s2->score() != ms) {
      54           33 :             return true;
      55              :         }
      56        16799 :         if (s1->score() != s2->score()) {
      57        12806 :             return false;
      58              :         }
      59         3993 :         if (staves) {
      60         1460 :             return toStaff(s1)->idx() < toStaff(s2)->idx();
      61              :         }
      62         2533 :         if (elements) {
      63              :             // Now we compare either two elements from master score
      64              :             // or two elements from excerpt.
      65         2533 :             EngravingItem* e1 = toEngravingItem(s1);
      66         2533 :             EngravingItem* e2 = toEngravingItem(s2);
      67         2533 :             const track_idx_t tr1 = e1->track();
      68         2533 :             const track_idx_t tr2 = e2->track();
      69         2533 :             if (tr1 == tr2) {
      70            6 :                 const Fraction tick1 = e1->tick();
      71            6 :                 const Fraction tick2 = e2->tick();
      72            6 :                 if (tick1 == tick2) {
      73            6 :                     Measure* m1 = e1->findMeasure();
      74            6 :                     Measure* m2 = e2->findMeasure();
      75            6 :                     if (!m1 || !m2) {
      76            0 :                         return false;
      77              :                     }
      78              : 
      79              :                     // MM rests are written to MSCX in the following order:
      80              :                     // 1) first measure of MM rest (m->hasMMRest() == true);
      81              :                     // 2) MM rest itself (m->isMMRest() == true);
      82              :                     // 3) other measures of MM rest (m->hasMMRest() == false).
      83              :                     //
      84              :                     // As mainElement() must find the first element that
      85              :                     // is going to be written to a file, MM rest writing
      86              :                     // order should also be considered.
      87              : 
      88            6 :                     if (m1->isMMRest() == m2->isMMRest()) {
      89              :                         // no difference if both are MM rests or both are usual measures
      90            6 :                         return false;
      91              :                     }
      92              : 
      93              :                     // MM rests may be generated but not written (e.g. if
      94              :                     // saving a file right after disabling MM rests)
      95            0 :                     bool mmRestsWritten = e1->style().styleB(Sid::createMultiMeasureRests);
      96            0 :                     if (m1->tick() == m2->tick()) {
      97              :                         // MM rests may be still enabled but the mmRest may have been removed by editing
      98              :                         // NOTE: the fact that we have linked clones between the original measure and the MMRest
      99              :                         // and we have to decide which one is the "main" one is really bad tech debt. We should not
     100              :                         // use linked clones for that. Needs fix in future. [M.S.]
     101            0 :                         bool oneIsMMRestCoveringOther = m1->mmRest() == m2 || m2->mmRest() == m1;
     102            0 :                         mmRestsWritten &= oneIsMMRestCoveringOther;
     103              :                     }
     104              : 
     105            0 :                     if (m1->isMMRest()) {
     106              :                         // m1 is earlier if m2 is *not* the first MM rest measure
     107            0 :                         return mmRestsWritten && !m2->hasMMRest();
     108              :                     }
     109            0 :                     if (m2->isMMRest()) {
     110              :                         // m1 is earlier if it *is* the first MM rest measure
     111            0 :                         return !mmRestsWritten || m1->hasMMRest();
     112              :                     }
     113            0 :                     return false;
     114              :                 }
     115            0 :                 return tick1 < tick2;
     116              :             }
     117         2527 :             return tr1 < tr2;
     118              :         }
     119            0 :         return false;
     120        16926 :     });
     121              : }
        

Generated by: LCOV version 2.0-1