LCOV - code coverage report
Current view: top level - muse/framework/draw - painter.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 59.9 % 324 194
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore-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 "painter.h"
      23              : 
      24              : #include "types/brush.h"
      25              : #include "types/painterpath.h"
      26              : 
      27              : #ifndef NO_QT_SUPPORT
      28              : #include "internal/qpainterprovider.h"
      29              : #endif
      30              : 
      31              : #include "log.h"
      32              : 
      33              : using namespace muse;
      34              : using namespace muse::draw;
      35              : 
      36              : IPaintProviderPtr Painter::extended;
      37              : bool PainterItemMarker::enabled = true;
      38              : 
      39            7 : Painter::Painter(IPaintProviderPtr provider, const std::string& name)
      40            7 :     : m_provider(provider), m_name(name)
      41              : {
      42            7 :     init();
      43            7 : }
      44              : 
      45              : #ifndef NO_QT_SUPPORT
      46           14 : Painter::Painter(QPaintDevice* dp, const std::string& name)
      47           14 :     : m_name(name)
      48              : {
      49           14 :     m_provider = QPainterProvider::make(dp);
      50           14 :     init();
      51           14 : }
      52              : 
      53            4 : Painter::Painter(QPainter* qp, const std::string& name, bool ownsQPainter)
      54            4 :     : m_name(name)
      55              : {
      56            4 :     m_provider = QPainterProvider::make(qp, ownsQPainter);
      57            4 :     init();
      58            4 : }
      59              : 
      60              : #endif
      61              : 
      62           25 : Painter::~Painter()
      63              : {
      64           25 :     endTarget(false);
      65           25 : }
      66              : 
      67           25 : void Painter::init()
      68              : {
      69           25 :     m_provider->beginTarget(m_name);
      70           25 :     if (extended) {
      71            0 :         extended->beginTarget(m_name);
      72              :     }
      73              : 
      74           25 :     State st;
      75           25 :     st.worldTransform = m_provider->transform();
      76           25 :     st.isWxF = true;
      77           25 :     st.transform = st.worldTransform;
      78              : 
      79           25 :     m_states = std::stack<State>();
      80           25 :     m_states.push(std::move(st));
      81           25 : }
      82              : 
      83           23 : IPaintProviderPtr Painter::provider() const
      84              : {
      85           23 :     return m_provider;
      86              : }
      87              : 
      88            0 : void Painter::setProvider(const IPaintProviderPtr& p, bool reinit)
      89              : {
      90            0 :     m_provider = p;
      91            0 :     if (reinit) {
      92            0 :         init();
      93              :     }
      94            0 : }
      95              : 
      96           16 : bool Painter::endDraw()
      97              : {
      98           16 :     return endTarget(true);
      99              : }
     100              : 
     101           41 : bool Painter::endTarget(bool endDraw)
     102              : {
     103           41 :     m_provider->beforeEndTargetHook(this);
     104           41 :     if (extended) {
     105            0 :         extended->beforeEndTargetHook(this);
     106              :     }
     107              : 
     108           41 :     bool ok = m_provider->endTarget(endDraw);
     109           41 :     if (extended) {
     110            0 :         extended->endTarget(endDraw);
     111              :     }
     112           41 :     return ok;
     113              : }
     114              : 
     115            0 : bool Painter::isActive() const
     116              : {
     117            0 :     return m_provider->isActive();
     118              : }
     119              : 
     120            9 : void Painter::beginObject(const std::string& name)
     121              : {
     122            9 :     m_provider->beginObject(name);
     123            9 :     if (extended) {
     124            0 :         extended->beginObject(name);
     125              :     }
     126            9 : }
     127              : 
     128            9 : void Painter::endObject()
     129              : {
     130            9 :     m_provider->endObject();
     131            9 :     if (extended) {
     132            0 :         extended->endObject();
     133              :     }
     134            9 : }
     135              : 
     136            6 : void Painter::setAntialiasing(bool arg)
     137              : {
     138            6 :     m_provider->setAntialiasing(arg);
     139            6 :     if (extended) {
     140            0 :         extended->setAntialiasing(arg);
     141              :     }
     142            6 : }
     143              : 
     144            0 : void Painter::setCompositionMode(CompositionMode mode)
     145              : {
     146            0 :     m_provider->setCompositionMode(mode);
     147            0 :     if (extended) {
     148            0 :         extended->setCompositionMode(mode);
     149              :     }
     150            0 : }
     151              : 
     152          502 : void Painter::setFont(const Font& font)
     153              : {
     154          502 :     m_provider->setFont(font);
     155          502 :     if (extended) {
     156            0 :         extended->setFont(font);
     157              :     }
     158          502 : }
     159              : 
     160          251 : const Font& Painter::font() const
     161              : {
     162          251 :     return m_provider->font();
     163              : }
     164              : 
     165          396 : void Painter::setPen(const Pen& pen)
     166              : {
     167          396 :     m_provider->setPen(pen);
     168          396 :     if (extended) {
     169            0 :         extended->setPen(pen);
     170              :     }
     171          396 : }
     172              : 
     173            0 : void Painter::setNoPen()
     174              : {
     175            0 :     setPen(Pen(PenStyle::NoPen));
     176            0 : }
     177              : 
     178            4 : const Pen& Painter::pen() const
     179              : {
     180            4 :     return m_provider->pen();
     181              : }
     182              : 
     183           10 : void Painter::setBrush(const Brush& brush)
     184              : {
     185           10 :     m_provider->setBrush(brush);
     186           10 :     if (extended) {
     187            0 :         extended->setBrush(brush);
     188              :     }
     189           10 : }
     190              : 
     191            4 : const Brush& Painter::brush() const
     192              : {
     193            4 :     return m_provider->brush();
     194              : }
     195              : 
     196          302 : void Painter::save()
     197              : {
     198          302 :     State newSt = m_states.top();
     199          302 :     m_states.push(newSt);
     200              : 
     201          302 :     m_provider->save();
     202          302 :     if (extended) {
     203            0 :         extended->save();
     204              :     }
     205          302 : }
     206              : 
     207          302 : void Painter::restore()
     208              : {
     209          302 :     if (m_states.size() > 0) {
     210          302 :         m_states.pop();
     211              :     }
     212              : 
     213          302 :     m_provider->restore();
     214          302 :     if (extended) {
     215            0 :         extended->restore();
     216              :     }
     217          302 : }
     218              : 
     219          251 : double Painter::deviceLogicalDpi() const
     220              : {
     221          251 :     return m_provider->deviceLogicalDpi();
     222              : }
     223              : 
     224            5 : void Painter::setWorldTransform(const Transform& matrix, bool combine)
     225              : {
     226            5 :     State& st = editableState();
     227            5 :     if (combine) {
     228            0 :         st.worldTransform = matrix * st.worldTransform;                        // combines
     229              :     } else {
     230            5 :         st.worldTransform = matrix;                                // set new matrix
     231              :     }
     232            5 :     st.isWxF = true;
     233            5 :     updateMatrix();
     234            5 : }
     235              : 
     236            5 : const Transform& Painter::worldTransform() const
     237              : {
     238            5 :     return state().worldTransform;
     239              : }
     240              : 
     241          251 : void Painter::scale(double sx, double sy)
     242              : {
     243          251 :     State& st = editableState();
     244          251 :     st.worldTransform.scale(sx, sy);
     245          251 :     st.isWxF = true;
     246          251 :     updateMatrix();
     247          251 : }
     248              : 
     249            0 : void Painter::rotate(double angle)
     250              : {
     251            0 :     State& st = editableState();
     252            0 :     st.worldTransform.rotate(angle);
     253            0 :     st.isWxF = true;
     254            0 :     updateMatrix();
     255            0 : }
     256              : 
     257          774 : void Painter::translate(double dx, double dy)
     258              : {
     259          774 :     State& st = editableState();
     260          774 :     st.worldTransform.translate(dx, dy);
     261          774 :     st.isWxF = true;
     262          774 :     updateMatrix();
     263          774 : }
     264              : 
     265            1 : RectF Painter::window() const
     266              : {
     267            1 :     return state().window;
     268              : }
     269              : 
     270           10 : void Painter::setWindow(const RectF& window)
     271              : {
     272           10 :     State& st = editableState();
     273           10 :     st.window = window;
     274           10 :     st.isVxF = true;
     275           10 :     updateViewTransform();
     276              : 
     277              :     // for debug purpose
     278           10 :     m_provider->setWindow(window);
     279           10 :     if (extended) {
     280            0 :         extended->setWindow(window);
     281              :     }
     282           10 : }
     283              : 
     284            1 : RectF Painter::viewport() const
     285              : {
     286            1 :     return state().viewport;
     287              : }
     288              : 
     289           11 : void Painter::setViewport(const RectF& viewport)
     290              : {
     291           11 :     State& st = editableState();
     292           11 :     st.viewport = viewport;
     293           11 :     st.isVxF = true;
     294           11 :     updateViewTransform();
     295              : 
     296              :     // for debug purpose
     297           11 :     m_provider->setViewport(viewport);
     298           11 :     if (extended) {
     299            0 :         extended->setViewport(viewport);
     300              :     }
     301           11 : }
     302              : 
     303              : // drawing functions
     304              : 
     305            0 : void Painter::fillPath(const PainterPath& path, const Brush& brush)
     306              : {
     307            0 :     Pen oldPen = this->pen();
     308            0 :     Brush oldBrush = this->brush();
     309            0 :     setPen(Pen(PenStyle::NoPen));
     310            0 :     setBrush(brush);
     311              : 
     312            0 :     drawPath(path);
     313              : 
     314            0 :     setPen(oldPen);
     315            0 :     setBrush(oldBrush);
     316            0 : }
     317              : 
     318            0 : void Painter::strokePath(const PainterPath& path, const Pen& pen)
     319              : {
     320            0 :     Pen oldPen = this->pen();
     321            0 :     Brush oldBrush = this->brush();
     322            0 :     setPen(pen);
     323            0 :     setBrush(BrushStyle::NoBrush);
     324              : 
     325            0 :     drawPath(path);
     326              : 
     327            0 :     setPen(oldPen);
     328            0 :     setBrush(oldBrush);
     329            0 : }
     330              : 
     331            6 : void Painter::drawPath(const PainterPath& path)
     332              : {
     333            6 :     m_provider->drawPath(path);
     334            6 :     if (extended) {
     335            0 :         extended->drawPath(path);
     336              :     }
     337            6 : }
     338              : 
     339          151 : void Painter::drawLines(const LineF* lines, size_t lineCount)
     340              : {
     341          382 :     for (size_t i = 0; i < lineCount; ++i) {
     342          231 :         PointF pts[2] = { lines[i].p1(), lines[i].p2() };
     343          231 :         if (pts[0] == pts[1]) {
     344            0 :             LOGE() << "draw point not implemented";
     345              :         }
     346          231 :         drawPolyline(pts, 2);
     347              :     }
     348          151 : }
     349              : 
     350            0 : void Painter::drawLines(const PointF* pointPairs, size_t lineCount)
     351              : {
     352              :     static_assert(sizeof(LineF) == 2 * sizeof(PointF), "must be: sizeof(LineF) == 2 * sizeof(PointF)");
     353              : 
     354            0 :     drawLines((const LineF*)pointPairs, lineCount);
     355            0 : }
     356              : 
     357            6 : void Painter::drawRects(const RectF* rects, size_t rectCount)
     358              : {
     359           12 :     for (size_t i = 0; i < rectCount; ++i) {
     360            6 :         PainterPath path;
     361            6 :         path.addRect(rects[i]);
     362            6 :         if (path.isEmpty()) {
     363            0 :             continue;
     364              :         }
     365            6 :         drawPath(path);
     366            6 :     }
     367            6 : }
     368              : 
     369            0 : void Painter::drawEllipse(const RectF& rect)
     370              : {
     371            0 :     PainterPath path;
     372            0 :     path.addEllipse(rect);
     373            0 :     m_provider->drawPath(path);
     374            0 :     if (extended) {
     375            0 :         extended->drawPath(path);
     376              :     }
     377            0 : }
     378              : 
     379          231 : void Painter::drawPolyline(const PointF* points, size_t pointCount)
     380              : {
     381          231 :     m_provider->drawPolygon(points, pointCount, PolygonMode::Polyline);
     382          231 :     if (extended) {
     383            0 :         extended->drawPolygon(points, pointCount, PolygonMode::Polyline);
     384              :     }
     385          231 : }
     386              : 
     387            0 : void Painter::drawPolygon(const PointF* points, size_t pointCount, FillRule fillRule)
     388              : {
     389            0 :     PolygonMode mode = (fillRule == FillRule::OddEvenFill) ? PolygonMode::OddEven : PolygonMode::Winding;
     390            0 :     m_provider->drawPolygon(points, pointCount, mode);
     391            0 :     if (extended) {
     392            0 :         extended->drawPolygon(points, pointCount, mode);
     393              :     }
     394            0 : }
     395              : 
     396            0 : void Painter::drawConvexPolygon(const PointF* points, size_t pointCount)
     397              : {
     398            0 :     m_provider->drawPolygon(points, pointCount, PolygonMode::Convex);
     399            0 :     if (extended) {
     400            0 :         extended->drawPolygon(points, pointCount, PolygonMode::Convex);
     401              :     }
     402            0 : }
     403              : 
     404            0 : void Painter::drawArc(const RectF& r, int a, int alen)
     405              : {
     406              :     //! NOTE Copied from QPainter source code
     407              : 
     408            0 :     RectF rect = r.normalized();
     409              : 
     410            0 :     PainterPath path;
     411            0 :     path.arcMoveTo(rect, a / 16.0);
     412            0 :     path.arcTo(rect, a / 16.0, alen / 16.0);
     413            0 :     strokePath(path, pen());
     414            0 : }
     415              : 
     416            0 : void Painter::drawRoundedRect(const RectF& rect, double xRadius, double yRadius)
     417              : {
     418            0 :     if (xRadius <= 0 || yRadius <= 0) {             // draw normal rectangle
     419            0 :         drawRect(rect);
     420            0 :         return;
     421              :     }
     422              : 
     423            0 :     PainterPath path;
     424            0 :     path.addRoundedRect(rect, xRadius, yRadius);
     425            0 :     drawPath(path);
     426            0 : }
     427              : 
     428          251 : void Painter::applyFontSizeScaling()
     429              : {
     430              :     static constexpr double MU_ENGRAVING_DPI = 1200; // Same as mu::engraving::DPI. TODO: pass as parameter.
     431          251 :     Font f = font();
     432          251 :     double scaledPointSize = f.pointSizeF() * MU_ENGRAVING_DPI / deviceLogicalDpi();
     433          251 :     f.setPointSizeF(scaledPointSize);
     434          251 :     setFont(f);
     435          251 : }
     436              : 
     437            0 : void Painter::drawText(const PointF& point, const String& text)
     438              : {
     439            0 :     applyFontSizeScaling();
     440              : 
     441            0 :     m_provider->drawText(point, text);
     442            0 :     if (extended) {
     443            0 :         extended->drawText(point, text);
     444              :     }
     445            0 : }
     446              : 
     447            0 : void Painter::drawText(const RectF& rect, Alignment alignment, TextFlags textFlags, const String& text)
     448              : {
     449            0 :     applyFontSizeScaling();
     450              : 
     451            0 :     m_provider->drawText(rect, alignment, textFlags, text);
     452            0 :     if (extended) {
     453            0 :         extended->drawText(rect, alignment, textFlags, text);
     454              :     }
     455            0 : }
     456              : 
     457          251 : void Painter::drawSymbol(const PointF& point, char32_t ucs4Code)
     458              : {
     459          251 :     applyFontSizeScaling();
     460              : 
     461          251 :     m_provider->drawSymbol(point, ucs4Code);
     462          251 :     if (extended) {
     463            0 :         extended->drawSymbol(point, ucs4Code);
     464              :     }
     465          251 : }
     466              : 
     467            4 : void Painter::fillRect(const RectF& rect, const Brush& brush)
     468              : {
     469            4 :     Pen oldPen = this->pen();
     470            4 :     Brush oldBrush = this->brush();
     471            4 :     setPen(Pen(PenStyle::NoPen));
     472            4 :     setBrush(brush);
     473              : 
     474            4 :     drawRect(rect);
     475              : 
     476            4 :     setBrush(oldBrush);
     477            4 :     setPen(oldPen);
     478            4 : }
     479              : 
     480            0 : void Painter::drawPixmap(const PointF& point, const Pixmap& pm)
     481              : {
     482            0 :     m_provider->drawPixmap(point, pm);
     483            0 :     if (extended) {
     484            0 :         extended->drawPixmap(point, pm);
     485              :     }
     486            0 : }
     487              : 
     488            0 : void Painter::drawTiledPixmap(const RectF& rect, const Pixmap& pm, const PointF& offset)
     489              : {
     490            0 :     m_provider->drawTiledPixmap(rect, pm, offset);
     491            0 :     if (extended) {
     492            0 :         extended->drawTiledPixmap(rect, pm, offset);
     493              :     }
     494            0 : }
     495              : 
     496              : #ifndef NO_QT_SUPPORT
     497            0 : void Painter::drawPixmap(const PointF& point, const QPixmap& pm)
     498              : {
     499            0 :     m_provider->drawPixmap(point, pm);
     500            0 :     if (extended) {
     501            0 :         extended->drawPixmap(point, pm);
     502              :     }
     503            0 : }
     504              : 
     505            0 : void Painter::drawTiledPixmap(const RectF& rect, const QPixmap& pm, const PointF& offset)
     506              : {
     507            0 :     m_provider->drawTiledPixmap(rect, pm, offset);
     508            0 :     if (extended) {
     509            0 :         extended->drawTiledPixmap(rect, pm, offset);
     510              :     }
     511            0 : }
     512              : 
     513              : #endif
     514              : 
     515         2123 : Painter::State& Painter::editableState()
     516              : {
     517         2123 :     return m_states.top();
     518              : }
     519              : 
     520            7 : const Painter::State& Painter::state() const
     521              : {
     522            7 :     return m_states.top();
     523              : }
     524              : 
     525           21 : void Painter::updateViewTransform()
     526              : {
     527           21 :     State& st = editableState();
     528           21 :     if (st.window.isNull()) {
     529            8 :         st.viewTransform = Transform();
     530            8 :         updateMatrix();
     531            8 :         return;
     532              :     }
     533              : 
     534           13 :     double scaleW = double(st.viewport.width()) / double(st.window.width());
     535           13 :     double scaleH = double(st.viewport.height()) / double(st.window.height());
     536           13 :     st.viewTransform = Transform(scaleW, 0, 0, scaleH, st.viewport.x() - st.window.x() * scaleW, st.viewport.y() - st.window.y() * scaleH);
     537           13 :     updateMatrix();
     538              : }
     539              : 
     540         1051 : void Painter::updateMatrix()
     541              : {
     542         1051 :     Painter::State& st = editableState();
     543         1051 :     st.transform = st.isWxF ? st.worldTransform : Transform();
     544         1051 :     if (st.isVxF) {
     545         1049 :         st.transform *= st.viewTransform;
     546              :     }
     547              : 
     548         1051 :     m_provider->setTransform(st.transform);
     549         1051 :     if (extended) {
     550            0 :         extended->setTransform(st.transform);
     551              :     }
     552         1051 : }
     553              : 
     554           10 : bool Painter::hasClipping() const
     555              : {
     556           10 :     return m_provider->hasClipping();
     557              : }
     558              : 
     559            5 : void Painter::setClipRect(const RectF& rect)
     560              : {
     561            5 :     m_provider->setClipRect(rect);
     562            5 : }
     563              : 
     564            0 : void Painter::setMask(const RectF& background, const std::vector<RectF>& maskRects)
     565              : {
     566            0 :     m_provider->setMask(background, maskRects);
     567            0 : }
     568              : 
     569           10 : void Painter::setClipping(bool enable)
     570              : {
     571           10 :     m_provider->setClipping(enable);
     572           10 : }
        

Generated by: LCOV version 2.0-1