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/qpainter_p.h"
49 #include "private/qpicture_p.h"
50 #include "private/qfont_p.h"
51 #include "QtGui/qpicture.h"
55 QAlphaPaintEngine::QAlphaPaintEngine(QAlphaPaintEnginePrivate &data, PaintEngineFeatures devcaps)
56 : QPaintEngine(data, devcaps)
61 QAlphaPaintEngine::~QAlphaPaintEngine()
66 bool QAlphaPaintEngine::begin(QPaintDevice *pdev)
68 Q_D(QAlphaPaintEngine);
70 d->m_continueCall = true;
75 d->m_savedcaps = gccaps;
78 d->m_alphaPen = false;
79 d->m_alphaBrush = false;
80 d->m_alphaOpacity = false;
81 d->m_hasalpha = false;
82 d->m_advancedPen = false;
83 d->m_advancedBrush = false;
84 d->m_complexTransform = false;
85 d->m_emulateProjectiveTransforms = false;
88 d->m_alphargn = QRegion();
89 d->m_cliprgn = QRegion();
91 d->m_transform = QTransform();
98 bool QAlphaPaintEngine::end()
100 Q_D(QAlphaPaintEngine);
102 d->m_continueCall = true;
103 if (d->m_pass != 0) {
111 void QAlphaPaintEngine::updateState(const QPaintEngineState &state)
113 Q_D(QAlphaPaintEngine);
115 DirtyFlags flags = state.state();
116 if (flags & QPaintEngine::DirtyTransform) {
117 d->m_transform = state.transform();
118 d->m_complexTransform = (d->m_transform.type() > QTransform::TxScale);
119 d->m_emulateProjectiveTransforms = !(d->m_savedcaps & QPaintEngine::PerspectiveTransform)
120 && !(d->m_savedcaps & QPaintEngine::AlphaBlend)
121 && (d->m_transform.type() >= QTransform::TxProject);
123 if (flags & QPaintEngine::DirtyPen) {
124 d->m_pen = state.pen();
125 if (d->m_pen.style() == Qt::NoPen) {
126 d->m_advancedPen = false;
127 d->m_alphaPen = false;
129 d->m_advancedPen = (d->m_pen.brush().style() != Qt::SolidPattern);
130 d->m_alphaPen = !d->m_pen.brush().isOpaque();
134 if (d->m_pass != 0) {
135 d->m_continueCall = true;
138 d->m_continueCall = false;
140 if (flags & QPaintEngine::DirtyOpacity) {
141 d->m_alphaOpacity = (state.opacity() != 1.0f);
144 if (flags & QPaintEngine::DirtyBrush) {
145 if (state.brush().style() == Qt::NoBrush) {
146 d->m_advancedBrush = false;
147 d->m_alphaBrush = false;
149 d->m_advancedBrush = (state.brush().style() != Qt::SolidPattern);
150 d->m_alphaBrush = !state.brush().isOpaque();
155 d->m_hasalpha = d->m_alphaOpacity || d->m_alphaBrush || d->m_alphaPen;
158 d->m_picengine->updateState(state);
161 void QAlphaPaintEngine::drawPath(const QPainterPath &path)
163 Q_D(QAlphaPaintEngine);
165 QRectF tr = d->addPenWidth(path);
167 if (d->m_pass == 0) {
168 d->m_continueCall = false;
169 if (d->m_hasalpha || d->m_advancedPen || d->m_advancedBrush
170 || d->m_emulateProjectiveTransforms)
175 d->m_picengine->drawPath(path);
177 d->m_continueCall = !d->fullyContained(tr);
181 void QAlphaPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
183 Q_D(QAlphaPaintEngine);
186 for (int i=0; i<pointCount; ++i)
187 poly.append(points[i]);
190 path.addPolygon(poly);
191 QRectF tr = d->addPenWidth(path);
193 if (d->m_pass == 0) {
194 d->m_continueCall = false;
195 if (d->m_hasalpha || d->m_advancedPen || d->m_advancedBrush
196 || d->m_emulateProjectiveTransforms)
202 d->m_picengine->drawPolygon(points, pointCount, mode);
204 d->m_continueCall = !d->fullyContained(tr);
208 void QAlphaPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
210 Q_D(QAlphaPaintEngine);
212 QRectF tr = d->m_transform.mapRect(r);
213 if (d->m_pass == 0) {
214 d->m_continueCall = false;
215 if (pm.hasAlpha() || d->m_alphaOpacity || d->m_complexTransform || pm.isQBitmap()) {
220 d->m_picengine->drawPixmap(r, pm, sr);
223 d->m_continueCall = !d->fullyContained(tr);
227 void QAlphaPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
229 Q_D(QAlphaPaintEngine);
231 QRectF tr(p.x(), p.y() - textItem.ascent(), textItem.width() + 5, textItem.ascent() + textItem.descent() + 5);
232 tr = d->m_transform.mapRect(tr);
234 if (d->m_pass == 0) {
235 d->m_continueCall = false;
236 if (d->m_alphaPen || d->m_alphaOpacity || d->m_advancedPen) {
239 if (d->m_picengine) {
240 d->m_picengine->drawTextItem(p, textItem);
243 d->m_continueCall = !d->fullyContained(tr);
247 void QAlphaPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s)
249 Q_D(QAlphaPaintEngine);
251 QRectF brect = d->m_transform.mapRect(r);
253 if (d->m_pass == 0) {
254 d->m_continueCall = false;
255 if (pixmap.hasAlpha() || d->m_alphaOpacity || d->m_complexTransform || pixmap.isQBitmap()) {
256 d->addAlphaRect(brect);
259 d->m_picengine->drawTiledPixmap(r, pixmap, s);
261 d->m_continueCall = !d->fullyContained(brect);
265 QRegion QAlphaPaintEngine::alphaClipping() const
267 Q_D(const QAlphaPaintEngine);
271 bool QAlphaPaintEngine::continueCall() const
273 Q_D(const QAlphaPaintEngine);
274 return d->m_continueCall;
277 void QAlphaPaintEngine::flushAndInit(bool init)
279 Q_D(QAlphaPaintEngine);
280 Q_ASSERT(d->m_pass == 0);
283 d->m_picpainter->end();
286 d->m_alphargn = d->m_alphargn.intersected(QRect(0, 0, d->m_pdev->width(), d->m_pdev->height()));
288 // just use the bounding rect if it's a complex region..
289 QVector<QRect> rects = d->m_alphargn.rects();
290 if (rects.size() > 10) {
291 QRect br = d->m_alphargn.boundingRect();
292 d->m_alphargn = QRegion(br);
297 d->m_cliprgn = d->m_alphargn;
299 // now replay the QPicture
300 ++d->m_pass; // we are now doing pass #2
303 gccaps = d->m_savedcaps;
306 d->resetState(painter());
308 // make sure the output from QPicture is unscaled
310 mtx.scale(1.0f / (qreal(d->m_pdev->logicalDpiX()) / qreal(qt_defaultDpiX())),
311 1.0f / (qreal(d->m_pdev->logicalDpiY()) / qreal(qt_defaultDpiY())));
312 painter()->setTransform(mtx);
313 painter()->drawPicture(0, 0, *d->m_pic);
315 d->m_cliprgn = QRegion();
316 d->resetState(painter());
318 // fill in the alpha images
319 for (int i=0; i<rects.size(); ++i)
320 d->drawAlphaImage(rects.at(i));
322 d->m_alphargn = QRegion();
324 painter()->restore();
326 --d->m_pass; // pass #2 finished
332 gccaps = PaintEngineFeatures(AllFeatures & ~QPaintEngine::ObjectBoundingModeGradients);
334 d->m_pic = new QPicture();
335 d->m_pic->d_ptr->in_memory_only = true;
336 d->m_picpainter = new QPainter(d->m_pic);
337 d->m_picengine = d->m_picpainter->paintEngine();
339 // When newPage() is called and the m_picpainter is recreated
340 // we have to copy the current state of the original printer
341 // painter back to the m_picpainter
342 d->m_picpainter->setPen(painter()->pen());
343 d->m_picpainter->setBrush(painter()->brush());
344 d->m_picpainter->setBrushOrigin(painter()->brushOrigin());
345 d->m_picpainter->setFont(painter()->font());
346 d->m_picpainter->setOpacity(painter()->opacity());
347 d->m_picpainter->setTransform(painter()->combinedTransform());
348 d->m_picengine->syncState();
352 void QAlphaPaintEngine::cleanUp()
354 Q_D(QAlphaPaintEngine);
356 delete d->m_picpainter;
364 QAlphaPaintEnginePrivate::QAlphaPaintEnginePrivate()
372 m_alphaOpacity(false),
373 m_advancedPen(false),
374 m_advancedBrush(false),
375 m_complexTransform(false)
380 QAlphaPaintEnginePrivate::~QAlphaPaintEnginePrivate()
386 QRectF QAlphaPaintEnginePrivate::addPenWidth(const QPainterPath &path)
388 Q_Q(QAlphaPaintEngine);
390 QPainterPath tmp = path;
392 if (m_pen.style() == Qt::NoPen)
393 return (path.controlPointRect() * m_transform).boundingRect();
394 bool cosmetic = qt_pen_is_cosmetic(m_pen, q->state->renderHints());
396 tmp = path * m_transform;
398 QPainterPathStroker stroker;
399 if (m_pen.widthF() == 0.0f)
400 stroker.setWidth(1.0);
402 stroker.setWidth(m_pen.widthF());
403 stroker.setJoinStyle(m_pen.joinStyle());
404 stroker.setCapStyle(m_pen.capStyle());
405 tmp = stroker.createStroke(tmp);
407 return tmp.controlPointRect();
409 return (tmp.controlPointRect() * m_transform).boundingRect();
412 QRect QAlphaPaintEnginePrivate::toRect(const QRectF &rect) const
415 r.setLeft(int(rect.left()));
416 r.setTop(int(rect.top()));
417 r.setRight(int(rect.right() + 1));
418 r.setBottom(int(rect.bottom() + 1));
422 void QAlphaPaintEnginePrivate::addAlphaRect(const QRectF &rect)
424 m_alphargn |= toRect(rect);
427 void QAlphaPaintEnginePrivate::drawAlphaImage(const QRectF &rect)
429 Q_Q(QAlphaPaintEngine);
431 qreal dpiX = qMax(m_pdev->logicalDpiX(), 300);
432 qreal dpiY = qMax(m_pdev->logicalDpiY(), 300);
433 qreal xscale = (dpiX / m_pdev->logicalDpiX());
434 qreal yscale = (dpiY / m_pdev->logicalDpiY());
437 picscale.scale(xscale, yscale);
439 const int tileSize = 2048;
440 QSize size((int(rect.width() * xscale)), int(rect.height() * yscale));
441 int divw = (size.width() / tileSize);
442 int divh = (size.height() / tileSize);
446 int incx = int(rect.width() / divw);
447 int incy = int(rect.height() / divh);
449 for (int y=0; y<divh; ++y) {
450 int ypos = int((incy * y) + rect.y());
451 int height = int((y == (divh - 1)) ? (rect.height() - (incy * y)) : incy) + 1;
453 for (int x=0; x<divw; ++x) {
454 int xpos = int((incx * x) + rect.x());
455 int width = int((x == (divw - 1)) ? (rect.width() - (incx * x)) : incx) + 1;
457 QSize imgsize((int)(width * xscale), (int)(height * yscale));
458 QImage img(imgsize, QImage::Format_RGB32);
459 img.fill(0xffffffff);
461 QPainter imgpainter(&img);
462 imgpainter.setTransform(picscale);
463 QPointF picpos(qreal(-xpos), qreal(-ypos));
464 imgpainter.drawPicture(picpos, *m_pic);
467 q->painter()->setTransform(QTransform());
468 QRect r(xpos, ypos, width, height);
469 q->painter()->drawImage(r, img);
474 bool QAlphaPaintEnginePrivate::fullyContained(const QRectF &rect) const
476 QRegion r(toRect(rect));
477 return (m_cliprgn.intersected(r) == r);
480 void QAlphaPaintEnginePrivate::resetState(QPainter *p)
483 p->setBrush(QBrush());
484 p->setBrushOrigin(0,0);
485 p->setBackground(QBrush());
487 p->setTransform(QTransform());
488 // The view transform is already recorded and included in the
489 // picture we're about to replay. If we don't turn if off,
490 // the view matrix will be applied twice.
491 p->setViewTransformEnabled(false);
492 p->setClipRegion(QRegion(), Qt::NoClip);
493 p->setClipPath(QPainterPath(), Qt::NoClip);
494 p->setClipping(false);
501 #endif // QT_NO_PRINTER