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 | |
45 | QT_BEGIN_NAMESPACE |
46 | |
47 | QEmulationPaintEngine::QEmulationPaintEngine(QPaintEngineEx *engine) |
48 | : real_engine(engine) |
49 | { |
50 | QPaintEngine::state = real_engine->state(); |
51 | } |
52 | |
53 | |
54 | QPaintEngine::Type QEmulationPaintEngine::type() const |
55 | { |
56 | return real_engine->type(); |
57 | } |
58 | |
59 | bool QEmulationPaintEngine::begin(QPaintDevice *) |
60 | { |
61 | return true; |
62 | } |
63 | |
64 | bool QEmulationPaintEngine::end() |
65 | { |
66 | return true; |
67 | } |
68 | |
69 | |
70 | QPainterState *QEmulationPaintEngine::createState(QPainterState *orig) const |
71 | { |
72 | return real_engine->createState(orig); |
73 | } |
74 | |
75 | static 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 | |
84 | void 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(©, 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(©, 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 | |
118 | void 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 | |
147 | void QEmulationPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op) |
148 | { |
149 | real_engine->clip(path, op); |
150 | } |
151 | |
152 | void 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 | |
159 | void 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(©, 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 | |
197 | void QEmulationPaintEngine::drawStaticTextItem(QStaticTextItem *item) |
198 | { |
199 | real_engine->drawStaticTextItem(item); |
200 | } |
201 | |
202 | void 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 | |
209 | void 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 | |
214 | void QEmulationPaintEngine::clipEnabledChanged() |
215 | { |
216 | real_engine->clipEnabledChanged(); |
217 | } |
218 | |
219 | void QEmulationPaintEngine::penChanged() |
220 | { |
221 | real_engine->penChanged(); |
222 | } |
223 | |
224 | void QEmulationPaintEngine::brushChanged() |
225 | { |
226 | real_engine->brushChanged(); |
227 | } |
228 | |
229 | void QEmulationPaintEngine::brushOriginChanged() |
230 | { |
231 | real_engine->brushOriginChanged(); |
232 | } |
233 | |
234 | void QEmulationPaintEngine::opacityChanged() |
235 | { |
236 | real_engine->opacityChanged(); |
237 | } |
238 | |
239 | void QEmulationPaintEngine::compositionModeChanged() |
240 | { |
241 | real_engine->compositionModeChanged(); |
242 | } |
243 | |
244 | void QEmulationPaintEngine::renderHintsChanged() |
245 | { |
246 | real_engine->renderHintsChanged(); |
247 | } |
248 | |
249 | void QEmulationPaintEngine::transformChanged() |
250 | { |
251 | real_engine->transformChanged(); |
252 | } |
253 | |
254 | void QEmulationPaintEngine::setState(QPainterState *s) |
255 | { |
256 | QPaintEngine::state = s; |
257 | real_engine->setState(s); |
258 | } |
259 | |
260 | void QEmulationPaintEngine::beginNativePainting() |
261 | { |
262 | real_engine->beginNativePainting(); |
263 | } |
264 | |
265 | void QEmulationPaintEngine::endNativePainting() |
266 | { |
267 | real_engine->endNativePainting(); |
268 | } |
269 | |
270 | void 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 | |
278 | QT_END_NAMESPACE |
279 | |