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