1 /*
2 * Copyright (c) 2016 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include "KoClipMaskPainter.h"
20
21 #include <QPainter>
22 #include <QPainterPath>
23 #include <QRectF>
24
25 #include "kis_assert.h"
26
27 struct Q_DECL_HIDDEN KoClipMaskPainter::Private
28 {
29 QPainter *globalPainter;
30
31 QImage shapeImage;
32 QImage maskImage;
33
34 QPainter shapePainter;
35 QPainter maskPainter;
36
37 QRect alignedGlobalClipRect;
38 };
39
KoClipMaskPainter(QPainter * painter,const QRectF & globalClipRect)40 KoClipMaskPainter::KoClipMaskPainter(QPainter *painter, const QRectF &globalClipRect)
41 : m_d(new Private)
42 {
43 m_d->globalPainter = painter;
44 m_d->alignedGlobalClipRect = globalClipRect.toAlignedRect();
45
46 m_d->shapeImage = QImage(m_d->alignedGlobalClipRect.size(), QImage::Format_ARGB32);
47 m_d->maskImage = QImage(m_d->alignedGlobalClipRect.size(), QImage::Format_ARGB32);
48
49 m_d->shapeImage.fill(0);
50 m_d->maskImage.fill(0);
51
52 QTransform moveToBufferTransform =
53 QTransform::fromTranslate(-m_d->alignedGlobalClipRect.x(),
54 -m_d->alignedGlobalClipRect.y());
55
56 m_d->shapePainter.begin(&m_d->shapeImage);
57 m_d->shapePainter.setTransform(moveToBufferTransform);
58 m_d->shapePainter.setTransform(painter->transform(), true);
59 if (painter->hasClipping()) {
60 m_d->shapePainter.setClipPath(painter->clipPath());
61 }
62 m_d->shapePainter.setOpacity(painter->opacity());
63 m_d->shapePainter.setBrush(painter->brush());
64 m_d->shapePainter.setPen(painter->pen());
65
66 m_d->maskPainter.begin(&m_d->maskImage);
67 m_d->maskPainter.setTransform(moveToBufferTransform);
68 m_d->maskPainter.setTransform(painter->transform(), true);
69 if (painter->hasClipping()) {
70 m_d->maskPainter.setClipPath(painter->clipPath());
71 }
72 m_d->maskPainter.setOpacity(painter->opacity());
73 m_d->maskPainter.setBrush(painter->brush());
74 m_d->maskPainter.setPen(painter->pen());
75 }
76
~KoClipMaskPainter()77 KoClipMaskPainter::~KoClipMaskPainter()
78 {
79 }
80
shapePainter()81 QPainter *KoClipMaskPainter::shapePainter()
82 {
83 return &m_d->shapePainter;
84 }
85
maskPainter()86 QPainter *KoClipMaskPainter::maskPainter()
87 {
88 return &m_d->maskPainter;
89 }
90
renderOnGlobalPainter()91 void KoClipMaskPainter::renderOnGlobalPainter()
92 {
93 KIS_ASSERT_RECOVER_RETURN(m_d->maskImage.size() == m_d->shapeImage.size());
94
95 for (int y = 0; y < m_d->maskImage.height(); y++) {
96 QRgb *shapeData = reinterpret_cast<QRgb*>(m_d->shapeImage.scanLine(y));
97 QRgb *maskData = reinterpret_cast<QRgb*>(m_d->maskImage.scanLine(y));
98
99 for (int x = 0; x < m_d->maskImage.width(); x++) {
100
101 const qreal normCoeff = 1.0 / 255.0 * 255.0;
102
103 qreal maskValue = qreal(qAlpha(*maskData)) *
104 (0.2125 * qRed(*maskData) +
105 0.7154 * qGreen(*maskData) +
106 0.0721 * qBlue(*maskData));
107
108 int alpha = qRound(maskValue * qAlpha(*shapeData) * normCoeff);
109
110 *shapeData = (alpha << 24) | (*shapeData & 0x00ffffff);
111
112 shapeData++;
113 maskData++;
114 }
115 }
116
117 KIS_ASSERT_RECOVER_RETURN(m_d->shapeImage.size() == m_d->alignedGlobalClipRect.size());
118 QPainterPath globalClipPath;
119
120 if (m_d->globalPainter->hasClipping()) {
121 globalClipPath = m_d->globalPainter->transform().map(m_d->globalPainter->clipPath());
122 }
123
124 m_d->globalPainter->save();
125
126 m_d->globalPainter->setTransform(QTransform());
127
128 if (!globalClipPath.isEmpty()) {
129 m_d->globalPainter->setClipPath(globalClipPath);
130 }
131
132 m_d->globalPainter->drawImage(m_d->alignedGlobalClipRect.topLeft(), m_d->shapeImage);
133 m_d->globalPainter->restore();
134 }
135
136