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 "qpainterprovider.h"
23 :
24 : #include <QPainter>
25 : #include <QRawFont>
26 : #include <QTextLayout>
27 : #include <QTextLine>
28 : #include <QGlyphRun>
29 : #include <QPixmapCache>
30 : #include <QStaticText>
31 : #include <QPainterPath>
32 :
33 : #include "draw/utils/drawlogger.h"
34 : #include "types/transform.h"
35 : #include "types/painterpath.h"
36 :
37 : #include "log.h"
38 :
39 : using namespace muse::draw;
40 :
41 18 : QPainterProvider::QPainterProvider(QPainter* painter, bool ownsPainter)
42 18 : : m_painter(painter), m_ownsPainter(ownsPainter), m_drawObjectsLogger(new DrawObjectsLogger())
43 : {
44 18 : if (painter->isActive()) {
45 18 : m_font = Font::fromQFont(m_painter->font(), Font::Type::Undefined);
46 18 : m_pen = Pen::fromQPen(m_painter->pen());
47 18 : m_brush = Brush::fromQBrush(m_painter->brush());
48 18 : m_transform = Transform::fromQTransform(m_painter->transform());
49 : }
50 18 : }
51 :
52 18 : QPainterProvider::~QPainterProvider()
53 : {
54 18 : if (m_ownsPainter) {
55 14 : delete m_painter;
56 : }
57 :
58 18 : delete m_drawObjectsLogger;
59 18 : }
60 :
61 14 : IPaintProviderPtr QPainterProvider::make(QPaintDevice* dp)
62 : {
63 14 : return std::make_shared<QPainterProvider>(new QPainter(dp), true);
64 : }
65 :
66 4 : IPaintProviderPtr QPainterProvider::make(QPainter* qp, bool ownsPainter)
67 : {
68 4 : return std::make_shared<QPainterProvider>(qp, ownsPainter);
69 : }
70 :
71 2 : QPainter* QPainterProvider::qpainter() const
72 : {
73 2 : return m_painter;
74 : }
75 :
76 18 : void QPainterProvider::beginTarget(const std::string&)
77 : {
78 18 : }
79 :
80 31 : void QPainterProvider::beforeEndTargetHook(Painter*)
81 : {
82 31 : }
83 :
84 31 : bool QPainterProvider::endTarget(bool endDraw)
85 : {
86 31 : if (endDraw) {
87 13 : return m_painter->end();
88 : }
89 18 : return true;
90 : }
91 :
92 0 : bool QPainterProvider::isActive() const
93 : {
94 0 : return m_painter->isActive();
95 : }
96 :
97 1 : void QPainterProvider::beginObject(const std::string& name)
98 : {
99 : UNUSED(name)
100 : //m_drawObjectsLogger->beginObject(name);
101 1 : }
102 :
103 1 : void QPainterProvider::endObject()
104 : {
105 : //m_drawObjectsLogger->endObject();
106 1 : }
107 :
108 435 : void QPainterProvider::setAntialiasing(bool arg)
109 : {
110 435 : m_painter->setRenderHint(QPainter::Antialiasing, arg);
111 435 : m_painter->setRenderHint(QPainter::TextAntialiasing, arg);
112 435 : }
113 :
114 434 : void QPainterProvider::setCompositionMode(CompositionMode mode)
115 : {
116 434 : auto toQPainter = [](CompositionMode mode) {
117 434 : switch (mode) {
118 434 : case CompositionMode::SourceOver: return QPainter::CompositionMode_SourceOver;
119 0 : case CompositionMode::HardLight: return QPainter::CompositionMode_HardLight;
120 0 : case CompositionMode::SourceIn: return QPainter::CompositionMode_SourceIn;
121 : }
122 0 : return QPainter::CompositionMode_SourceOver;
123 : };
124 434 : m_painter->setCompositionMode(toQPainter(mode));
125 434 : }
126 :
127 4 : void QPainterProvider::setWindow(const RectF& window)
128 : {
129 : // no need set
130 : UNUSED(window);
131 4 : }
132 :
133 4 : void QPainterProvider::setViewport(const RectF& viewport)
134 : {
135 : // no need set
136 : UNUSED(viewport);
137 4 : }
138 :
139 540 : void QPainterProvider::setFont(const Font& font)
140 : {
141 540 : if (m_font != font) {
142 125 : m_painter->setFont(font.toQFont());
143 125 : m_font = font;
144 : }
145 540 : }
146 :
147 53 : const Font& QPainterProvider::font() const
148 : {
149 53 : return m_font;
150 : }
151 :
152 522 : void QPainterProvider::setPen(const Pen& pen)
153 : {
154 522 : m_pen = pen;
155 522 : m_painter->setPen(Pen::toQPen(m_pen));
156 522 : }
157 :
158 0 : void QPainterProvider::setNoPen()
159 : {
160 0 : m_pen = Pen(PenStyle::NoPen);
161 0 : m_painter->setPen(Pen::toQPen(m_pen));
162 0 : }
163 :
164 0 : const Pen& QPainterProvider::pen() const
165 : {
166 0 : return m_pen;
167 : }
168 :
169 441 : void QPainterProvider::setBrush(const Brush& brush)
170 : {
171 441 : m_brush = brush;
172 441 : m_painter->setBrush(Brush::toQBrush(m_brush));
173 441 : }
174 :
175 0 : const Brush& QPainterProvider::brush() const
176 : {
177 0 : return m_brush;
178 : }
179 :
180 64 : void QPainterProvider::save()
181 : {
182 64 : m_painter->save();
183 64 : }
184 :
185 64 : void QPainterProvider::restore()
186 : {
187 64 : m_painter->restore();
188 64 : m_font = Font::fromQFont(m_painter->font(), Font::Type::Undefined);
189 64 : m_pen = Pen::fromQPen(m_painter->pen());
190 64 : m_brush = Brush::fromQBrush(m_painter->brush());
191 64 : m_transform = Transform::fromQTransform(m_painter->transform());
192 64 : }
193 :
194 53 : double QPainterProvider::deviceLogicalDpi() const
195 : {
196 53 : return m_painter->device()->logicalDpiX();
197 : }
198 :
199 660 : void QPainterProvider::setTransform(const Transform& transform)
200 : {
201 660 : m_transform = transform;
202 660 : m_painter->setTransform(Transform::toQTransform(m_transform));
203 660 : }
204 :
205 26 : const Transform& QPainterProvider::transform() const
206 : {
207 26 : return m_transform;
208 : }
209 :
210 : // drawing functions
211 :
212 7 : void QPainterProvider::drawPath(const PainterPath& path)
213 : {
214 7 : m_painter->drawPath(PainterPath::toQPainterPath(path));
215 7 : }
216 :
217 308 : void QPainterProvider::drawPolygon(const PointF* points, size_t pointCount, PolygonMode mode)
218 : {
219 : static_assert(sizeof(QPointF) == sizeof(PointF), "sizeof(QPointF) and sizeof(PointF) must be equal");
220 :
221 308 : const QPointF* qpoints = reinterpret_cast<const QPointF*>(points);
222 :
223 308 : switch (mode) {
224 0 : case PolygonMode::OddEven: {
225 0 : m_painter->drawPolygon(qpoints, int(pointCount), Qt::OddEvenFill);
226 0 : } break;
227 0 : case PolygonMode::Winding: {
228 0 : m_painter->drawPolygon(qpoints, int(pointCount), Qt::WindingFill);
229 0 : } break;
230 0 : case PolygonMode::Convex: {
231 0 : m_painter->drawConvexPolygon(qpoints, int(pointCount));
232 0 : } break;
233 308 : case PolygonMode::Polyline: {
234 308 : m_painter->drawPolyline(qpoints, int(pointCount));
235 308 : } break;
236 : }
237 308 : }
238 :
239 317 : void QPainterProvider::drawText(const PointF& point, const String& text)
240 : {
241 317 : QPointF p = point.toQPointF();
242 317 : QString t = text.toQString();
243 317 : m_painter->drawText(p, t);
244 317 : }
245 :
246 0 : void QPainterProvider::drawText(const RectF& rect, Alignment alignment, TextFlags textFlags, const String& text)
247 : {
248 0 : int flags = static_cast<int>(alignment) | static_cast<int>(textFlags);
249 0 : m_painter->drawText(rect.toQRectF(), flags, text.toQString());
250 0 : }
251 :
252 53 : void QPainterProvider::drawSymbol(const PointF& point, char32_t ucs4Code)
253 : {
254 54 : static QHash<char32_t, QString> cache;
255 53 : if (!cache.contains(ucs4Code)) {
256 8 : cache[ucs4Code] = QString::fromUcs4(&ucs4Code, 1);
257 : }
258 :
259 53 : drawText(point, cache.value(ucs4Code));
260 53 : }
261 :
262 0 : void QPainterProvider::drawPixmap(const PointF& point, const Pixmap& pm)
263 : {
264 0 : QString key = QString::number(pm.key());
265 0 : QPixmap pixmap;
266 0 : if (!QPixmapCache::find(key, &pixmap)) {
267 0 : pixmap.loadFromData(pm.data().toQByteArrayNoCopy());
268 0 : QPixmapCache::insert(key, pixmap);
269 : }
270 :
271 0 : m_painter->drawPixmap(QPointF(point.x(), point.y()), pixmap);
272 0 : }
273 :
274 0 : void QPainterProvider::drawTiledPixmap(const RectF& rect, const Pixmap& pm, const PointF& offset)
275 : {
276 0 : QString key = QString::number(pm.key());
277 0 : QPixmap pixmap;
278 0 : if (!QPixmapCache::find(key, &pixmap)) {
279 0 : pixmap.loadFromData(pm.data().toQByteArrayNoCopy());
280 0 : QPixmapCache::insert(key, pixmap);
281 : }
282 :
283 0 : m_painter->drawTiledPixmap(rect.toQRectF(), pixmap, QPointF(offset.x(), offset.y()));
284 0 : }
285 :
286 0 : void QPainterProvider::drawPixmap(const PointF& point, const QPixmap& pm)
287 : {
288 0 : m_painter->drawPixmap(QPointF(point.x(), point.y()), pm);
289 0 : }
290 :
291 0 : void QPainterProvider::drawTiledPixmap(const RectF& rect, const QPixmap& pm, const PointF& offset)
292 : {
293 0 : m_painter->drawTiledPixmap(rect.toQRectF(), pm, QPointF(offset.x(), offset.y()));
294 0 : }
295 :
296 2 : bool QPainterProvider::hasClipping() const
297 : {
298 2 : return m_painter->hasClipping();
299 : }
300 :
301 1 : void QPainterProvider::setClipRect(const RectF& rect)
302 : {
303 1 : m_painter->setClipRect(rect.toQRectF());
304 1 : }
305 :
306 0 : void QPainterProvider::setMask(const RectF& background, const std::vector<RectF>& maskRects)
307 : {
308 0 : if (maskRects.empty()) {
309 0 : m_painter->setClipPath(QPainterPath(), Qt::NoClip);
310 0 : return;
311 : }
312 :
313 0 : QPainterPath backgroundPath;
314 0 : backgroundPath.addRect(background.toQRectF());
315 :
316 0 : QPainterPath exclusionRegion;
317 0 : exclusionRegion.setFillRule(Qt::WindingFill);
318 0 : for (const RectF& rect : maskRects) {
319 0 : exclusionRegion.addRect(rect.toQRectF());
320 : }
321 :
322 0 : QPainterPath mask = backgroundPath.subtracted(exclusionRegion);
323 :
324 0 : m_painter->setClipPath(mask);
325 0 : }
326 :
327 2 : void QPainterProvider::setClipping(bool enable)
328 : {
329 2 : m_painter->setClipping(enable);
330 2 : }
|