1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
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::drawImage(const QRectF &r, const QImage &image, const QRectF &sr)
228 Q_D(QAlphaPaintEngine);
230 QRectF tr = d->m_transform.mapRect(r);
231 if (d->m_pass == 0) {
232 d->m_continueCall = false;
233 if (image.hasAlphaChannel() || d->m_alphaOpacity || d->m_complexTransform) {
238 d->m_picengine->drawImage(r, image, sr);
241 d->m_continueCall = !d->fullyContained(tr);
245 void QAlphaPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
247 Q_D(QAlphaPaintEngine);
249 QRectF tr(p.x(), p.y() - textItem.ascent(), textItem.width() + 5, textItem.ascent() + textItem.descent() + 5);
250 tr = d->m_transform.mapRect(tr);
252 if (d->m_pass == 0) {
253 d->m_continueCall = false;
254 if (d->m_alphaPen || d->m_alphaOpacity || d->m_advancedPen) {
257 if (d->m_picengine) {
258 d->m_picengine->drawTextItem(p, textItem);
261 d->m_continueCall = !d->fullyContained(tr);
265 void QAlphaPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s)
267 Q_D(QAlphaPaintEngine);
269 QRectF brect = d->m_transform.mapRect(r);
271 if (d->m_pass == 0) {
272 d->m_continueCall = false;
273 if (pixmap.hasAlpha() || d->m_alphaOpacity || d->m_complexTransform || pixmap.isQBitmap()) {
274 d->addAlphaRect(brect);
277 d->m_picengine->drawTiledPixmap(r, pixmap, s);
279 d->m_continueCall = !d->fullyContained(brect);
283 QRegion QAlphaPaintEngine::alphaClipping() const
285 Q_D(const QAlphaPaintEngine);
289 bool QAlphaPaintEngine::continueCall() const
291 Q_D(const QAlphaPaintEngine);
292 return d->m_continueCall;
295 void QAlphaPaintEngine::flushAndInit(bool init)
297 Q_D(QAlphaPaintEngine);
298 Q_ASSERT(d->m_pass == 0);
301 d->m_picpainter->end();
304 d->m_alphargn = d->m_alphargn.intersected(QRect(0, 0, d->m_pdev->width(), d->m_pdev->height()));
306 // just use the bounding rect if it's a complex region..
307 QVector<QRect> rects = d->m_alphargn.rects();
308 if (rects.size() > 10) {
309 QRect br = d->m_alphargn.boundingRect();
310 d->m_alphargn = QRegion(br);
315 d->m_cliprgn = d->m_alphargn;
317 // now replay the QPicture
318 ++d->m_pass; // we are now doing pass #2
321 gccaps = d->m_savedcaps;
324 d->resetState(painter());
326 // make sure the output from QPicture is unscaled
328 mtx.scale(1.0f / (qreal(d->m_pdev->logicalDpiX()) / qreal(qt_defaultDpiX())),
329 1.0f / (qreal(d->m_pdev->logicalDpiY()) / qreal(qt_defaultDpiY())));
330 painter()->setTransform(mtx);
331 painter()->drawPicture(0, 0, *d->m_pic);
333 d->m_cliprgn = QRegion();
334 d->resetState(painter());
336 // fill in the alpha images
337 for (int i=0; i<rects.size(); ++i)
338 d->drawAlphaImage(rects.at(i));
340 d->m_alphargn = QRegion();
342 painter()->restore();
344 --d->m_pass; // pass #2 finished
350 gccaps = PaintEngineFeatures(AllFeatures & ~QPaintEngine::ObjectBoundingModeGradients);
352 d->m_pic = new QPicture();
353 d->m_pic->d_ptr->in_memory_only = true;
354 d->m_picpainter = new QPainter(d->m_pic);
355 d->m_picengine = d->m_picpainter->paintEngine();
357 // When newPage() is called and the m_picpainter is recreated
358 // we have to copy the current state of the original printer
359 // painter back to the m_picpainter
360 d->m_picpainter->setPen(painter()->pen());
361 d->m_picpainter->setBrush(painter()->brush());
362 d->m_picpainter->setBrushOrigin(painter()->brushOrigin());
363 d->m_picpainter->setFont(painter()->font());
364 d->m_picpainter->setOpacity(painter()->opacity());
365 d->m_picpainter->setTransform(painter()->combinedTransform());
366 d->m_picengine->syncState();
370 void QAlphaPaintEngine::cleanUp()
372 Q_D(QAlphaPaintEngine);
374 delete d->m_picpainter;
382 QAlphaPaintEnginePrivate::QAlphaPaintEnginePrivate()
390 m_alphaOpacity(false),
391 m_advancedPen(false),
392 m_advancedBrush(false),
393 m_complexTransform(false)
398 QAlphaPaintEnginePrivate::~QAlphaPaintEnginePrivate()
404 QRectF QAlphaPaintEnginePrivate::addPenWidth(const QPainterPath &path)
406 QPainterPath tmp = path;
408 if (m_pen.style() == Qt::NoPen)
409 return (path.controlPointRect() * m_transform).boundingRect();
410 if (m_pen.isCosmetic())
411 tmp = path * m_transform;
413 QPainterPathStroker stroker;
414 if (m_pen.widthF() == 0.0f)
415 stroker.setWidth(1.0);
417 stroker.setWidth(m_pen.widthF());
418 stroker.setJoinStyle(m_pen.joinStyle());
419 stroker.setCapStyle(m_pen.capStyle());
420 tmp = stroker.createStroke(tmp);
421 if (m_pen.isCosmetic())
422 return tmp.controlPointRect();
424 return (tmp.controlPointRect() * m_transform).boundingRect();
427 QRect QAlphaPaintEnginePrivate::toRect(const QRectF &rect) const
430 r.setLeft(int(rect.left()));
431 r.setTop(int(rect.top()));
432 r.setRight(int(rect.right() + 1));
433 r.setBottom(int(rect.bottom() + 1));
437 void QAlphaPaintEnginePrivate::addAlphaRect(const QRectF &rect)
439 m_alphargn |= toRect(rect);
442 void QAlphaPaintEnginePrivate::drawAlphaImage(const QRectF &rect)
444 Q_Q(QAlphaPaintEngine);
446 qreal dpiX = qMax(m_pdev->logicalDpiX(), 300);
447 qreal dpiY = qMax(m_pdev->logicalDpiY(), 300);
448 qreal xscale = (dpiX / m_pdev->logicalDpiX());
449 qreal yscale = (dpiY / m_pdev->logicalDpiY());
452 picscale.scale(xscale, yscale);
454 const int tileSize = 2048;
455 QSize size((int(rect.width() * xscale)), int(rect.height() * yscale));
456 int divw = (size.width() / tileSize);
457 int divh = (size.height() / tileSize);
461 int incx = int(rect.width() / divw);
462 int incy = int(rect.height() / divh);
464 for (int y=0; y<divh; ++y) {
465 int ypos = int((incy * y) + rect.y());
466 int height = int((y == (divh - 1)) ? (rect.height() - (incy * y)) : incy) + 1;
468 for (int x=0; x<divw; ++x) {
469 int xpos = int((incx * x) + rect.x());
470 int width = int((x == (divw - 1)) ? (rect.width() - (incx * x)) : incx) + 1;
472 QSize imgsize((int)(width * xscale), (int)(height * yscale));
473 QImage img(imgsize, QImage::Format_RGB32);
474 img.fill(0xffffffff);
476 QPainter imgpainter(&img);
477 imgpainter.setTransform(picscale);
478 QPointF picpos(qreal(-xpos), qreal(-ypos));
479 imgpainter.drawPicture(picpos, *m_pic);
482 q->painter()->setTransform(QTransform());
483 QRect r(xpos, ypos, width, height);
484 q->painter()->drawImage(r, img);
489 bool QAlphaPaintEnginePrivate::fullyContained(const QRectF &rect) const
491 QRegion r(toRect(rect));
492 return (m_cliprgn.intersected(r) == r);
495 void QAlphaPaintEnginePrivate::resetState(QPainter *p)
498 p->setBrush(QBrush());
499 p->setBrushOrigin(0,0);
500 p->setBackground(QBrush());
502 p->setTransform(QTransform());
503 // The view transform is already recorded and included in the
504 // picture we're about to replay. If we don't turn if off,
505 // the view matrix will be applied twice.
506 p->setViewTransformEnabled(false);
507 p->setClipRegion(QRegion(), Qt::NoClip);
508 p->setClipPath(QPainterPath(), Qt::NoClip);
509 p->setClipping(false);
516 #endif // QT_NO_PRINTER