1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the QtGui module of the Qt Toolkit.
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 Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
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 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
46 #include "private/qpaintengine_alpha_p.h"
48 #include "private/qpicture_p.h"
49 #include "private/qfont_p.h"
50 #include "QtGui/qpicture.h"
54 QAlphaPaintEngine::QAlphaPaintEngine(QAlphaPaintEnginePrivate &data, PaintEngineFeatures devcaps)
55 : QPaintEngine(data, devcaps)
60 QAlphaPaintEngine::~QAlphaPaintEngine()
65 bool QAlphaPaintEngine::begin(QPaintDevice *pdev)
67 Q_D(QAlphaPaintEngine);
69 d->m_continueCall = true;
74 d->m_savedcaps = gccaps;
77 d->m_alphaPen = false;
78 d->m_alphaBrush = false;
79 d->m_alphaOpacity = false;
80 d->m_hasalpha = false;
81 d->m_advancedPen = false;
82 d->m_advancedBrush = false;
83 d->m_complexTransform = false;
84 d->m_emulateProjectiveTransforms = false;
87 d->m_alphargn = QRegion();
88 d->m_cliprgn = QRegion();
90 d->m_transform = QTransform();
97 bool QAlphaPaintEngine::end()
99 Q_D(QAlphaPaintEngine);
101 d->m_continueCall = true;
102 if (d->m_pass != 0) {
110 void QAlphaPaintEngine::updateState(const QPaintEngineState &state)
112 Q_D(QAlphaPaintEngine);
114 DirtyFlags flags = state.state();
115 if (flags & QPaintEngine::DirtyTransform) {
116 d->m_transform = state.transform();
117 d->m_complexTransform = (d->m_transform.type() > QTransform::TxScale);
118 d->m_emulateProjectiveTransforms = !(d->m_savedcaps & QPaintEngine::PerspectiveTransform)
119 && !(d->m_savedcaps & QPaintEngine::AlphaBlend)
120 && (d->m_transform.type() >= QTransform::TxProject);
122 if (flags & QPaintEngine::DirtyPen) {
123 d->m_pen = state.pen();
124 if (d->m_pen.style() == Qt::NoPen) {
125 d->m_advancedPen = false;
126 d->m_alphaPen = false;
128 d->m_advancedPen = (d->m_pen.brush().style() != Qt::SolidPattern);
129 d->m_alphaPen = !d->m_pen.brush().isOpaque();
133 if (d->m_pass != 0) {
134 d->m_continueCall = true;
137 d->m_continueCall = false;
139 if (flags & QPaintEngine::DirtyOpacity) {
140 d->m_alphaOpacity = (state.opacity() != 1.0f);
143 if (flags & QPaintEngine::DirtyBrush) {
144 if (state.brush().style() == Qt::NoBrush) {
145 d->m_advancedBrush = false;
146 d->m_alphaBrush = false;
148 d->m_advancedBrush = (state.brush().style() != Qt::SolidPattern);
149 d->m_alphaBrush = !state.brush().isOpaque();
154 d->m_hasalpha = d->m_alphaOpacity || d->m_alphaBrush || d->m_alphaPen;
157 d->m_picengine->updateState(state);
160 void QAlphaPaintEngine::drawPath(const QPainterPath &path)
162 Q_D(QAlphaPaintEngine);
164 QRectF tr = d->addPenWidth(path);
166 if (d->m_pass == 0) {
167 d->m_continueCall = false;
168 if (d->m_hasalpha || d->m_advancedPen || d->m_advancedBrush
169 || d->m_emulateProjectiveTransforms)
174 d->m_picengine->drawPath(path);
176 d->m_continueCall = !d->fullyContained(tr);
180 void QAlphaPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
182 Q_D(QAlphaPaintEngine);
185 for (int i=0; i<pointCount; ++i)
186 poly.append(points[i]);
189 path.addPolygon(poly);
190 QRectF tr = d->addPenWidth(path);
192 if (d->m_pass == 0) {
193 d->m_continueCall = false;
194 if (d->m_hasalpha || d->m_advancedPen || d->m_advancedBrush
195 || d->m_emulateProjectiveTransforms)
201 d->m_picengine->drawPolygon(points, pointCount, mode);
203 d->m_continueCall = !d->fullyContained(tr);
207 void QAlphaPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
209 Q_D(QAlphaPaintEngine);
211 QRectF tr = d->m_transform.mapRect(r);
212 if (d->m_pass == 0) {
213 d->m_continueCall = false;
214 if (pm.hasAlpha() || d->m_alphaOpacity || d->m_complexTransform || pm.isQBitmap()) {
219 d->m_picengine->drawPixmap(r, pm, sr);
222 d->m_continueCall = !d->fullyContained(tr);
226 void QAlphaPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
228 Q_D(QAlphaPaintEngine);
230 QRectF tr(p.x(), p.y() - textItem.ascent(), textItem.width() + 5, textItem.ascent() + textItem.descent() + 5);
231 tr = d->m_transform.mapRect(tr);
233 if (d->m_pass == 0) {
234 d->m_continueCall = false;
235 if (d->m_alphaPen || d->m_alphaOpacity || d->m_advancedPen) {
238 if (d->m_picengine) {
239 d->m_picengine->drawTextItem(p, textItem);
242 d->m_continueCall = !d->fullyContained(tr);
246 void QAlphaPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s)
248 Q_D(QAlphaPaintEngine);
250 QRectF brect = d->m_transform.mapRect(r);
252 if (d->m_pass == 0) {
253 d->m_continueCall = false;
254 if (pixmap.hasAlpha() || d->m_alphaOpacity || d->m_complexTransform || pixmap.isQBitmap()) {
255 d->addAlphaRect(brect);
258 d->m_picengine->drawTiledPixmap(r, pixmap, s);
260 d->m_continueCall = !d->fullyContained(brect);
264 QRegion QAlphaPaintEngine::alphaClipping() const
266 Q_D(const QAlphaPaintEngine);
270 bool QAlphaPaintEngine::continueCall() const
272 Q_D(const QAlphaPaintEngine);
273 return d->m_continueCall;
276 void QAlphaPaintEngine::flushAndInit(bool init)
278 Q_D(QAlphaPaintEngine);
279 Q_ASSERT(d->m_pass == 0);
282 d->m_picpainter->end();
285 d->m_alphargn = d->m_alphargn.intersected(QRect(0, 0, d->m_pdev->width(), d->m_pdev->height()));
287 // just use the bounding rect if it's a complex region..
288 QVector<QRect> rects = d->m_alphargn.rects();
289 if (rects.size() > 10) {
290 QRect br = d->m_alphargn.boundingRect();
291 d->m_alphargn = QRegion(br);
296 d->m_cliprgn = d->m_alphargn;
298 // now replay the QPicture
299 ++d->m_pass; // we are now doing pass #2
302 gccaps = d->m_savedcaps;
305 d->resetState(painter());
307 // make sure the output from QPicture is unscaled
309 mtx.scale(1.0f / (qreal(d->m_pdev->logicalDpiX()) / qreal(qt_defaultDpiX())),
310 1.0f / (qreal(d->m_pdev->logicalDpiY()) / qreal(qt_defaultDpiY())));
311 painter()->setTransform(mtx);
312 painter()->drawPicture(0, 0, *d->m_pic);
314 d->m_cliprgn = QRegion();
315 d->resetState(painter());
317 // fill in the alpha images
318 for (int i=0; i<rects.size(); ++i)
319 d->drawAlphaImage(rects.at(i));
321 d->m_alphargn = QRegion();
323 painter()->restore();
325 --d->m_pass; // pass #2 finished
331 gccaps = PaintEngineFeatures(AllFeatures & ~QPaintEngine::ObjectBoundingModeGradients);
333 d->m_pic = new QPicture();
334 d->m_pic->d_ptr->in_memory_only = true;
335 d->m_picpainter = new QPainter(d->m_pic);
336 d->m_picengine = d->m_picpainter->paintEngine();
338 // When newPage() is called and the m_picpainter is recreated
339 // we have to copy the current state of the original printer
340 // painter back to the m_picpainter
341 d->m_picpainter->setPen(painter()->pen());
342 d->m_picpainter->setBrush(painter()->brush());
343 d->m_picpainter->setBrushOrigin(painter()->brushOrigin());
344 d->m_picpainter->setFont(painter()->font());
345 d->m_picpainter->setOpacity(painter()->opacity());
346 d->m_picpainter->setTransform(painter()->combinedTransform());
347 d->m_picengine->syncState();
351 void QAlphaPaintEngine::cleanUp()
353 Q_D(QAlphaPaintEngine);
355 delete d->m_picpainter;
363 QAlphaPaintEnginePrivate::QAlphaPaintEnginePrivate()
371 m_alphaOpacity(false),
372 m_advancedPen(false),
373 m_advancedBrush(false),
374 m_complexTransform(false)
379 QAlphaPaintEnginePrivate::~QAlphaPaintEnginePrivate()
385 QRectF QAlphaPaintEnginePrivate::addPenWidth(const QPainterPath &path)
387 QPainterPath tmp = path;
389 if (m_pen.style() == Qt::NoPen)
390 return (path.controlPointRect() * m_transform).boundingRect();
391 if (m_pen.isCosmetic())
392 tmp = path * m_transform;
394 QPainterPathStroker stroker;
395 if (m_pen.widthF() == 0.0f)
396 stroker.setWidth(1.0);
398 stroker.setWidth(m_pen.widthF());
399 stroker.setJoinStyle(m_pen.joinStyle());
400 stroker.setCapStyle(m_pen.capStyle());
401 tmp = stroker.createStroke(tmp);
402 if (m_pen.isCosmetic())
403 return tmp.controlPointRect();
405 return (tmp.controlPointRect() * m_transform).boundingRect();
408 QRect QAlphaPaintEnginePrivate::toRect(const QRectF &rect) const
411 r.setLeft(int(rect.left()));
412 r.setTop(int(rect.top()));
413 r.setRight(int(rect.right() + 1));
414 r.setBottom(int(rect.bottom() + 1));
418 void QAlphaPaintEnginePrivate::addAlphaRect(const QRectF &rect)
420 m_alphargn |= toRect(rect);
423 void QAlphaPaintEnginePrivate::drawAlphaImage(const QRectF &rect)
425 Q_Q(QAlphaPaintEngine);
427 qreal dpiX = qMax(m_pdev->logicalDpiX(), 300);
428 qreal dpiY = qMax(m_pdev->logicalDpiY(), 300);
429 qreal xscale = (dpiX / m_pdev->logicalDpiX());
430 qreal yscale = (dpiY / m_pdev->logicalDpiY());
433 picscale.scale(xscale, yscale);
435 const int tileSize = 2048;
436 QSize size((int(rect.width() * xscale)), int(rect.height() * yscale));
437 int divw = (size.width() / tileSize);
438 int divh = (size.height() / tileSize);
442 int incx = int(rect.width() / divw);
443 int incy = int(rect.height() / divh);
445 for (int y=0; y<divh; ++y) {
446 int ypos = int((incy * y) + rect.y());
447 int height = int((y == (divh - 1)) ? (rect.height() - (incy * y)) : incy) + 1;
449 for (int x=0; x<divw; ++x) {
450 int xpos = int((incx * x) + rect.x());
451 int width = int((x == (divw - 1)) ? (rect.width() - (incx * x)) : incx) + 1;
453 QSize imgsize((int)(width * xscale), (int)(height * yscale));
454 QImage img(imgsize, QImage::Format_RGB32);
455 img.fill(0xffffffff);
457 QPainter imgpainter(&img);
458 imgpainter.setTransform(picscale);
459 QPointF picpos(qreal(-xpos), qreal(-ypos));
460 imgpainter.drawPicture(picpos, *m_pic);
463 q->painter()->setTransform(QTransform());
464 QRect r(xpos, ypos, width, height);
465 q->painter()->drawImage(r, img);
470 bool QAlphaPaintEnginePrivate::fullyContained(const QRectF &rect) const
472 QRegion r(toRect(rect));
473 return (m_cliprgn.intersected(r) == r);
476 void QAlphaPaintEnginePrivate::resetState(QPainter *p)
479 p->setBrush(QBrush());
480 p->setBrushOrigin(0,0);
481 p->setBackground(QBrush());
483 p->setTransform(QTransform());
484 // The view transform is already recorded and included in the
485 // picture we're about to replay. If we don't turn if off,
486 // the view matrix will be applied twice.
487 p->setViewTransformEnabled(false);
488 p->setClipRegion(QRegion(), Qt::NoClip);
489 p->setClipPath(QPainterPath(), Qt::NoClip);
490 p->setClipping(false);
497 #endif // QT_NO_PRINTER