1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include <private/qemulationpaintengine_p.h>
41#include <private/qpainter_p.h>
42#include <private/qtextengine_p.h>
43#include <qdebug.h>
44
45QT_BEGIN_NAMESPACE
46
47QEmulationPaintEngine::QEmulationPaintEngine(QPaintEngineEx *engine)
48 : real_engine(engine)
49{
50 QPaintEngine::state = real_engine->state();
51}
52
53
54QPaintEngine::Type QEmulationPaintEngine::type() const
55{
56 return real_engine->type();
57}
58
59bool QEmulationPaintEngine::begin(QPaintDevice *)
60{
61 return true;
62}
63
64bool QEmulationPaintEngine::end()
65{
66 return true;
67}
68
69
70QPainterState *QEmulationPaintEngine::createState(QPainterState *orig) const
71{
72 return real_engine->createState(orig);
73}
74
75static inline void combineXForm(QBrush *brush, const QRectF &r)
76{
77 QTransform t(r.width(), 0, 0, r.height(), r.x(), r.y());
78 if (brush->gradient() && brush->gradient()->coordinateMode() != QGradient::ObjectMode)
79 brush->setTransform(t * brush->transform()); // compat mode
80 else
81 brush->setTransform(brush->transform() * t);
82}
83
84void QEmulationPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
85{
86 QPainterState *s = state();
87
88 if (s->bgMode == Qt::OpaqueMode) {
89 Qt::BrushStyle style = brush.style();
90 if ((style >= Qt::Dense1Pattern && style <= Qt::DiagCrossPattern) || (style == Qt::TexturePattern ))
91 real_engine->fill(path, s->bgBrush);
92 }
93
94 Qt::BrushStyle style = qbrush_style(brush);
95 if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern) {
96 QGradient::CoordinateMode coMode = brush.gradient()->coordinateMode();
97 if (coMode > QGradient::LogicalMode) {
98 QBrush copy = brush;
99 const QPaintDevice *d = real_engine->painter()->device();
100 QRectF r = (coMode == QGradient::StretchToDeviceMode) ? QRectF(0, 0, d->width(), d->height()) : path.controlPointRect();
101 combineXForm(&copy, r);
102 real_engine->fill(path, copy);
103 return;
104 }
105 } else if (style == Qt::TexturePattern) {
106 qreal dpr = qHasPixmapTexture(brush) ? brush.texture().devicePixelRatio() : brush.textureImage().devicePixelRatio();
107 if (!qFuzzyCompare(dpr, qreal(1.0))) {
108 QBrush copy = brush;
109 combineXForm(&copy, QRectF(0, 0, 1.0/dpr, 1.0/dpr));
110 real_engine->fill(path, copy);
111 return;
112 }
113 }
114
115 real_engine->fill(path, brush);
116}
117
118void QEmulationPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
119{
120 QPainterState *s = state();
121
122 if (s->bgMode == Qt::OpaqueMode && pen.style() > Qt::SolidLine) {
123 QPen bgPen = pen;
124 bgPen.setBrush(s->bgBrush);
125 bgPen.setStyle(Qt::SolidLine);
126 real_engine->stroke(path, bgPen);
127 }
128
129 QBrush brush = pen.brush();
130 QPen copy = pen;
131 Qt::BrushStyle style = qbrush_style(brush);
132 if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern ) {
133 QGradient::CoordinateMode coMode = brush.gradient()->coordinateMode();
134 if (coMode > QGradient::LogicalMode) {
135 const QPaintDevice *d = real_engine->painter()->device();
136 QRectF r = (coMode == QGradient::StretchToDeviceMode) ? QRectF(0, 0, d->width(), d->height()) : path.controlPointRect();
137 combineXForm(&brush, r);
138 copy.setBrush(brush);
139 real_engine->stroke(path, copy);
140 return;
141 }
142 }
143
144 real_engine->stroke(path, pen);
145}
146
147void QEmulationPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
148{
149 real_engine->clip(path, op);
150}
151
152void QEmulationPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
153{
154 if (state()->bgMode == Qt::OpaqueMode && pm.isQBitmap())
155 fillBGRect(r);
156 real_engine->drawPixmap(r, pm, sr);
157}
158
159void QEmulationPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
160{
161 if (state()->bgMode == Qt::OpaqueMode) {
162 const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
163 QRectF rect(p.x(), p.y() - ti.ascent.toReal(), ti.width.toReal(), (ti.ascent + ti.descent).toReal());
164 fillBGRect(rect);
165 }
166
167 QPainterState *s = state();
168 Qt::BrushStyle style = qbrush_style(s->pen.brush());
169 if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern)
170 {
171 QPen savedPen = s->pen;
172 QGradient g = *s->pen.brush().gradient();
173
174 if (g.coordinateMode() > QGradient::LogicalMode) {
175 QBrush copy = s->pen.brush();
176 const QPaintDevice *d = real_engine->painter()->device();
177 const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
178 QRectF r = (g.coordinateMode() == QGradient::StretchToDeviceMode) ?
179 QRectF(0, 0, d->width(), d->height()) :
180 QRectF(p.x(), p.y() - ti.ascent.toReal(), ti.width.toReal(), (ti.ascent + ti.descent + 1).toReal());
181 combineXForm(&copy, r);
182 g.setCoordinateMode(QGradient::LogicalMode);
183 QBrush brush(g);
184 brush.setTransform(copy.transform());
185 s->pen.setBrush(brush);
186 penChanged();
187 real_engine->drawTextItem(p, textItem);
188 s->pen = savedPen;
189 penChanged();
190 return;
191 }
192 }
193
194 real_engine->drawTextItem(p, textItem);
195}
196
197void QEmulationPaintEngine::drawStaticTextItem(QStaticTextItem *item)
198{
199 real_engine->drawStaticTextItem(item);
200}
201
202void QEmulationPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s)
203{
204 if (state()->bgMode == Qt::OpaqueMode && pixmap.isQBitmap())
205 fillBGRect(r);
206 real_engine->drawTiledPixmap(r, pixmap, s);
207}
208
209void QEmulationPaintEngine::drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, Qt::ImageConversionFlags flags)
210{
211 real_engine->drawImage(r, pm, sr, flags);
212}
213
214void QEmulationPaintEngine::clipEnabledChanged()
215{
216 real_engine->clipEnabledChanged();
217}
218
219void QEmulationPaintEngine::penChanged()
220{
221 real_engine->penChanged();
222}
223
224void QEmulationPaintEngine::brushChanged()
225{
226 real_engine->brushChanged();
227}
228
229void QEmulationPaintEngine::brushOriginChanged()
230{
231 real_engine->brushOriginChanged();
232}
233
234void QEmulationPaintEngine::opacityChanged()
235{
236 real_engine->opacityChanged();
237}
238
239void QEmulationPaintEngine::compositionModeChanged()
240{
241 real_engine->compositionModeChanged();
242}
243
244void QEmulationPaintEngine::renderHintsChanged()
245{
246 real_engine->renderHintsChanged();
247}
248
249void QEmulationPaintEngine::transformChanged()
250{
251 real_engine->transformChanged();
252}
253
254void QEmulationPaintEngine::setState(QPainterState *s)
255{
256 QPaintEngine::state = s;
257 real_engine->setState(s);
258}
259
260void QEmulationPaintEngine::beginNativePainting()
261{
262 real_engine->beginNativePainting();
263}
264
265void QEmulationPaintEngine::endNativePainting()
266{
267 real_engine->endNativePainting();
268}
269
270void QEmulationPaintEngine::fillBGRect(const QRectF &r)
271{
272 qreal pts[] = { r.x(), r.y(), r.x() + r.width(), r.y(),
273 r.x() + r.width(), r.y() + r.height(), r.x(), r.y() + r.height() };
274 QVectorPath vp(pts, 4, nullptr, QVectorPath::RectangleHint);
275 real_engine->fill(vp, state()->bgBrush);
276}
277
278QT_END_NAMESPACE
279