LCOV - code coverage report
Current view: top level - src/engraving/rendering/score - debugpaint.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 0.0 % 168 0
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 "debugpaint.h"
      23              : 
      24              : #include "iengravingconfiguration.h"
      25              : #include "iengravingcontextconfiguration.h" // IWYU pragma: keep
      26              : 
      27              : //#include "accessibility/accessibleitem.h"
      28              : #include "dom/page.h"
      29              : #include "dom/score.h"
      30              : #include "dom/system.h"
      31              : #include "dom/measurebase.h"
      32              : #include "dom/measure.h"
      33              : #include "dom/note.h"
      34              : #include "dom/segment.h"
      35              : 
      36              : #include "tdraw.h"
      37              : 
      38              : #include "log.h"
      39              : 
      40              : using namespace muse::draw;
      41              : using namespace mu::engraving;
      42              : using namespace mu::engraving::rendering::score;
      43              : 
      44              : static const Color DEBUG_ELTREE_SELECTED_COLOR(164, 0, 0);
      45              : 
      46              : /// Generates a seemingly random but stable color based on a pointer address.
      47              : /// If we would use really random colors, they would change on every redraw.
      48              : /// Additional advantage: being able to see when an element is replaced with
      49              : /// a different element during layout.
      50            0 : static Color colorForPointer(const void* ptr)
      51              : {
      52              :     static constexpr uint32_t rgbTotalMax = 600;
      53              :     static constexpr uint32_t mask = 0xFFFF;
      54              :     static constexpr double max = mask + 1.0;
      55              : 
      56            0 :     auto hash = std::hash<const void*> {}(ptr);
      57            0 :     uint32_t cmpnt1 = hash & mask;
      58            0 :     uint32_t cmpnt2 = (hash >> 16) & mask;
      59              : 
      60            0 :     uint32_t r = std::clamp(uint32_t(cmpnt1 / max * 255), 30u, 255u);
      61            0 :     uint32_t g = std::clamp(uint32_t(cmpnt2 / max * 255), 30u, 255u);
      62            0 :     uint32_t b = std::clamp(rgbTotalMax - r - g,          30u, 255u);
      63              : 
      64            0 :     return Color(r, g, b, 128);
      65              : }
      66              : 
      67            0 : void DebugPaint::paintElementDebug(Painter& painter, const EngravingItem* item)
      68              : {
      69              :     // Elements tree
      70            0 :     bool isDiagnosticSelected = item->score()->elementsProvider() ? item->score()->elementsProvider()->isSelected(item) : false;
      71              : 
      72            0 :     PointF pos(item->pagePos());
      73            0 :     painter.translate(pos);
      74              : 
      75            0 :     RectF bbox = item->ldata()->bbox();
      76              : 
      77            0 :     if (item->isType(ElementType::SEGMENT)) {
      78            0 :         if (muse::RealIsNull(bbox.height())) {
      79            0 :             bbox.setHeight(10.0);
      80            0 :             LOGD() << "Segment bbox height is null";
      81              :         }
      82              :     }
      83              : 
      84            0 :     if (!bbox.isEmpty()) {
      85              :         // Draw shape
      86            0 :         if (item->configuration()->debuggingOptions().colorElementShapes
      87            0 :             && !item->isPage() && !item->isSystem() && !item->isStaffLines() && !item->isBox()) {
      88            0 :             PainterPath path;
      89            0 :             path.setFillRule(PainterPath::FillRule::WindingFill);
      90              : 
      91            0 :             Shape shape = item->shape();
      92            0 :             for (const RectF& rect : shape.elements()) {
      93            0 :                 path.addRect(rect);
      94              :             }
      95              : 
      96            0 :             painter.setPen(PenStyle::NoPen);
      97            0 :             painter.setBrush(colorForPointer(item));
      98            0 :             painter.drawPath(path);
      99            0 :         }
     100              : 
     101            0 :         if (item->configuration()->debuggingOptions().showElementMasks) {
     102            0 :             PainterPath path;
     103            0 :             path.setFillRule(PainterPath::FillRule::WindingFill);
     104            0 :             for (const ShapeElement& el : item->ldata()->mask().elements()) {
     105            0 :                 path.addRect(el);
     106              :             }
     107              : 
     108            0 :             painter.setPen(Color::BLACK);
     109            0 :             Brush brush(Color::BLACK);
     110            0 :             brush.setStyle(BrushStyle::BDiagPattern);
     111            0 :             painter.setBrush(brush);
     112            0 :             painter.drawPath(path);
     113            0 :         }
     114              : 
     115            0 :         if (item->isNote() && item->configuration()->debuggingOptions().showLineAttachPoints) {
     116            0 :             painter.setPen(Color::RED);
     117            0 :             Brush brush(Color::RED);
     118            0 :             painter.setBrush(brush);
     119            0 :             double radius = 0.1 * item->spatium();
     120            0 :             for (const LineAttachPoint& lap : toNote(item)->lineAttachPoints()) {
     121            0 :                 PointF point = lap.pos();
     122            0 :                 painter.drawEllipse(RectF(point.x() - radius, point.y() - radius, 2 * radius, 2 * radius));
     123              :             }
     124            0 :         }
     125              : 
     126              :         // Draw bbox
     127            0 :         if (isDiagnosticSelected || item->configuration()->debuggingOptions().showElementBoundingRects) {
     128            0 :             double scaling = painter.worldTransform().m11() / item->contextConfiguration()->guiScaling();
     129            0 :             Pen borderPen(DEBUG_ELTREE_SELECTED_COLOR, (item->selected() ? 2.0 : 1.0) / scaling);
     130              : 
     131            0 :             painter.setPen(borderPen);
     132            0 :             painter.setBrush(BrushStyle::NoBrush);
     133            0 :             painter.drawRect(bbox);
     134            0 :         }
     135              :     }
     136              : 
     137            0 :     painter.translate(-pos);
     138            0 : }
     139              : 
     140            0 : void DebugPaint::paintPageDebug(Painter& painter, const Page* page, const std::vector<EngravingItem*>& items)
     141              : {
     142            0 :     if (items.empty()) {
     143            0 :         return;
     144              :     }
     145              : 
     146            0 :     auto options = items.front()->configuration()->debuggingOptions();
     147            0 :     if (!options.anyEnabled()) {
     148            0 :         return;
     149              :     }
     150              : 
     151            0 :     IF_ASSERT_FAILED(page) {
     152            0 :         return;
     153              :     }
     154              : 
     155            0 :     Score* score = page->score();
     156              : 
     157            0 :     IF_ASSERT_FAILED(score) {
     158            0 :         return;
     159              :     }
     160              : 
     161            0 :     double scaling = painter.worldTransform().m11() / items.front()->contextConfiguration()->guiScaling();
     162              : 
     163            0 :     painter.save();
     164              : 
     165            0 :     for (const EngravingItem* item : items) {
     166            0 :         paintElementDebug(painter, item);
     167              :     }
     168              : 
     169            0 :     if (options.showSystemBoundingRects) {
     170            0 :         painter.setBrush(BrushStyle::NoBrush);
     171            0 :         painter.setPen(Pen(Color::BLACK, 3.0 / scaling));
     172              : 
     173            0 :         for (const System* system : page->systems()) {
     174            0 :             PointF pt(system->ldata()->pos());
     175            0 :             double h = system->height() + system->minBottom() + system->minTop();
     176            0 :             painter.translate(pt);
     177            0 :             RectF rect(0.0, -system->minTop(), system->width(), h);
     178            0 :             painter.drawRect(rect);
     179            0 :             painter.translate(-pt);
     180              :         }
     181              :     }
     182              : 
     183            0 :     if (options.showSkylines) {
     184            0 :         for (const System* system : page->systems()) {
     185            0 :             for (const SysStaff* ss : system->staves()) {
     186            0 :                 if (!ss->show()) {
     187            0 :                     continue;
     188              :                 }
     189              : 
     190            0 :                 PointF pt(system->ldata()->pos().x(), system->ldata()->pos().y() + ss->y());
     191            0 :                 painter.translate(pt);
     192            0 :                 ss->skyline().paint(painter, 3);
     193            0 :                 painter.translate(-pt);
     194              :             }
     195              :         }
     196              :     }
     197              : 
     198            0 :     if (options.colorSegmentShapes) {
     199            0 :         painter.setPen(PenStyle::NoPen);
     200              : 
     201            0 :         for (const System* system : page->systems()) {
     202            0 :             for (const MeasureBase* mb : system->measures()) {
     203            0 :                 if (!mb->isMeasure()) {
     204            0 :                     continue;
     205              :                 }
     206              : 
     207            0 :                 const Measure* m = toMeasure(mb);
     208              : 
     209            0 :                 for (const Segment* s = m->first(); s; s = s->next()) {
     210            0 :                     if (!s->enabled()) {
     211            0 :                         continue;
     212              :                     }
     213              : 
     214            0 :                     painter.setBrush(colorForPointer(s));
     215              : 
     216            0 :                     for (staff_idx_t i = 0; i < score->nstaves(); ++i) {
     217            0 :                         PainterPath path;
     218            0 :                         path.setFillRule(PainterPath::FillRule::WindingFill);
     219              : 
     220            0 :                         Shape shape = s->shapes().at(i);
     221            0 :                         for (const RectF& rect : shape.elements()) {
     222            0 :                             path.addRect(rect);
     223              :                         }
     224              : 
     225            0 :                         PointF pt(s->pos().x() + m->pos().x() + system->pos().x(),
     226            0 :                                   system->staffYpage(i));
     227            0 :                         painter.translate(pt);
     228            0 :                         painter.drawPath(path);
     229            0 :                         painter.translate(-pt);
     230            0 :                     }
     231              :                 }
     232              :             }
     233              :         }
     234              :     }
     235              : 
     236            0 :     if (options.showSegmentShapes) {
     237            0 :         painter.setBrush(BrushStyle::NoBrush);
     238            0 :         Pen pen(Color(238, 238, 144), 2.0 / scaling);
     239              : 
     240            0 :         for (const System* system : page->systems()) {
     241            0 :             for (const MeasureBase* mb : system->measures()) {
     242            0 :                 if (!mb->isMeasure()) {
     243            0 :                     continue;
     244              :                 }
     245              : 
     246            0 :                 const Measure* m = toMeasure(mb);
     247              : 
     248            0 :                 for (const Segment* s = m->first(); s; s = s->next()) {
     249            0 :                     pen.setStyle(s->enabled() ? PenStyle::SolidLine : PenStyle::DotLine);
     250            0 :                     painter.setPen(pen);
     251              : 
     252            0 :                     for (staff_idx_t i = 0; i < score->nstaves(); ++i) {
     253            0 :                         PointF pt(s->pos().x() + m->pos().x() + system->pos().x(),
     254            0 :                                   system->staffYpage(i));
     255            0 :                         painter.translate(pt);
     256            0 :                         s->shapes().at(i).paint(painter);
     257            0 :                         painter.translate(-pt);
     258              :                     }
     259              :                 }
     260              :             }
     261              :         }
     262            0 :     }
     263              : 
     264            0 :     if (options.markEmptyStaffVisibilityOverrides) {
     265            0 :         double _spatium = score->style().spatium();
     266              : 
     267            0 :         for (const System* system : page->systems()) {
     268            0 :             for (const MeasureBase* mb : system->measures()) {
     269            0 :                 if (!mb->isMeasure()) {
     270            0 :                     continue;
     271              :                 }
     272              : 
     273            0 :                 const Measure* m = toMeasure(mb);
     274              : 
     275            0 :                 for (staff_idx_t staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) {
     276            0 :                     AutoOnOff hideIfEmpty = m->hideStaffIfEmpty(staffIdx);
     277              : 
     278            0 :                     Color fillColor;
     279            0 :                     switch (hideIfEmpty) {
     280            0 :                     case AutoOnOff::ON:
     281            0 :                         fillColor = Color(255, 0, 0, 128);
     282            0 :                         break;
     283            0 :                     case AutoOnOff::OFF:
     284            0 :                         fillColor = Color(0, 0, 255, 128);
     285            0 :                         break;
     286            0 :                     default:
     287            0 :                         continue;
     288              :                     }
     289              : 
     290            0 :                     painter.setBrush(fillColor);
     291            0 :                     painter.setPen(PenStyle::NoPen);
     292              : 
     293            0 :                     painter.drawRect(m->staffPageBoundingRect(staffIdx).adjusted(0, -_spatium, 0, _spatium));
     294              :                 }
     295              :             }
     296              :         }
     297              :     }
     298              : 
     299            0 :     if (options.markCorruptedMeasures && score->hasCorruptedMeasures()) {
     300            0 :         painter.setPen(Pen(Color::RED, 4.0));
     301            0 :         painter.setBrush(BrushStyle::NoBrush);
     302              : 
     303            0 :         double _spatium = score->style().spatium();
     304              : 
     305            0 :         for (const System* system : page->systems()) {
     306            0 :             for (const MeasureBase* mb : system->measures()) {
     307            0 :                 if (!mb->isMeasure()) {
     308            0 :                     continue;
     309              :                 }
     310              : 
     311            0 :                 const Measure* m = toMeasure(mb);
     312            0 :                 for (size_t staffIdx = 0; staffIdx < score->nstaves(); staffIdx++) {
     313            0 :                     if (m->corrupted(staffIdx)) {
     314            0 :                         painter.drawRect(m->staffPageBoundingRect(staffIdx).adjusted(0, -_spatium, 0, _spatium));
     315              :                     }
     316              :                 }
     317              :             }
     318              :         }
     319              :     }
     320              : 
     321            0 :     painter.restore();
     322              : }
        

Generated by: LCOV version 2.0-1