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 
QEmulationPaintEngine(QPaintEngineEx * engine)47 QEmulationPaintEngine::QEmulationPaintEngine(QPaintEngineEx *engine)
48     : real_engine(engine)
49 {
50     QPaintEngine::state = real_engine->state();
51 }
52 
53 
type() const54 QPaintEngine::Type QEmulationPaintEngine::type() const
55 {
56     return real_engine->type();
57 }
58 
begin(QPaintDevice *)59 bool QEmulationPaintEngine::begin(QPaintDevice *)
60 {
61     return true;
62 }
63 
end()64 bool QEmulationPaintEngine::end()
65 {
66     return true;
67 }
68 
69 
createState(QPainterState * orig) const70 QPainterState *QEmulationPaintEngine::createState(QPainterState *orig) const
71 {
72     return real_engine->createState(orig);
73 }
74 
combineXForm(QBrush * brush,const QRectF & r)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 
fill(const QVectorPath & path,const QBrush & brush)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(&copy, r);
102             real_engine->fill(path, copy);
103             return;
104         }
105     } else if (style == Qt::TexturePattern) {
106         qreal dpr = qHasPixmapTexture(brush) ? brush.texture().devicePixelRatioF() : brush.textureImage().devicePixelRatioF();
107         if (!qFuzzyCompare(dpr, 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 
stroke(const QVectorPath & path,const QPen & pen)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 
clip(const QVectorPath & path,Qt::ClipOperation op)147 void QEmulationPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
148 {
149     real_engine->clip(path, op);
150 }
151 
drawPixmap(const QRectF & r,const QPixmap & pm,const QRectF & sr)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 
drawTextItem(const QPointF & p,const QTextItem & textItem)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(&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 
drawStaticTextItem(QStaticTextItem * item)197 void QEmulationPaintEngine::drawStaticTextItem(QStaticTextItem *item)
198 {
199     real_engine->drawStaticTextItem(item);
200 }
201 
drawTiledPixmap(const QRectF & r,const QPixmap & pixmap,const QPointF & s)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 
drawImage(const QRectF & r,const QImage & pm,const QRectF & sr,Qt::ImageConversionFlags flags)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 
clipEnabledChanged()214 void QEmulationPaintEngine::clipEnabledChanged()
215 {
216     real_engine->clipEnabledChanged();
217 }
218 
penChanged()219 void QEmulationPaintEngine::penChanged()
220 {
221     real_engine->penChanged();
222 }
223 
brushChanged()224 void QEmulationPaintEngine::brushChanged()
225 {
226     real_engine->brushChanged();
227 }
228 
brushOriginChanged()229 void QEmulationPaintEngine::brushOriginChanged()
230 {
231     real_engine->brushOriginChanged();
232 }
233 
opacityChanged()234 void QEmulationPaintEngine::opacityChanged()
235 {
236     real_engine->opacityChanged();
237 }
238 
compositionModeChanged()239 void QEmulationPaintEngine::compositionModeChanged()
240 {
241     real_engine->compositionModeChanged();
242 }
243 
renderHintsChanged()244 void QEmulationPaintEngine::renderHintsChanged()
245 {
246     real_engine->renderHintsChanged();
247 }
248 
transformChanged()249 void QEmulationPaintEngine::transformChanged()
250 {
251     real_engine->transformChanged();
252 }
253 
setState(QPainterState * s)254 void QEmulationPaintEngine::setState(QPainterState *s)
255 {
256     QPaintEngine::state = s;
257     real_engine->setState(s);
258 }
259 
beginNativePainting()260 void QEmulationPaintEngine::beginNativePainting()
261 {
262     real_engine->beginNativePainting();
263 }
264 
endNativePainting()265 void QEmulationPaintEngine::endNativePainting()
266 {
267     real_engine->endNativePainting();
268 }
269 
fillBGRect(const QRectF & r)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