e3312f2db7779b61245a6417a4f802a6487838f5
[profile/ivi/qtbase.git] / src / printsupport / kernel / qpaintengine_alpha.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
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 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.
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 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.
24 **
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.
28 **
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.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <qglobal.h>
43
44 #ifndef QT_NO_PRINTER
45 #include <qdebug.h>
46 #include "private/qpaintengine_alpha_p.h"
47
48 #include "private/qpicture_p.h"
49 #include "private/qfont_p.h"
50 #include "QtGui/qpicture.h"
51
52 QT_BEGIN_NAMESPACE
53
54 QAlphaPaintEngine::QAlphaPaintEngine(QAlphaPaintEnginePrivate &data, PaintEngineFeatures devcaps)
55     : QPaintEngine(data, devcaps)
56 {
57
58 }
59
60 QAlphaPaintEngine::~QAlphaPaintEngine()
61 {
62
63 }
64
65 bool QAlphaPaintEngine::begin(QPaintDevice *pdev)
66 {
67     Q_D(QAlphaPaintEngine);
68
69     d->m_continueCall = true;
70     if (d->m_pass != 0) {
71         return true;
72     }
73
74     d->m_savedcaps = gccaps;
75     d->m_pdev = pdev;
76
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;
85
86     // clear alpha region
87     d->m_alphargn = QRegion();
88     d->m_cliprgn = QRegion();
89     d->m_pen = QPen();
90     d->m_transform = QTransform();
91
92     flushAndInit();
93
94     return true;
95 }
96
97 bool QAlphaPaintEngine::end()
98 {
99     Q_D(QAlphaPaintEngine);
100
101     d->m_continueCall = true;
102     if (d->m_pass != 0) {
103         return true;
104     }
105
106     flushAndInit(false);
107     return true;
108 }
109
110 void QAlphaPaintEngine::updateState(const QPaintEngineState &state)
111 {
112     Q_D(QAlphaPaintEngine);
113
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);
121     }
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;
127         } else {
128             d->m_advancedPen = (d->m_pen.brush().style() != Qt::SolidPattern);
129             d->m_alphaPen = !d->m_pen.brush().isOpaque();
130         }
131     }
132
133     if (d->m_pass != 0) {
134         d->m_continueCall = true;
135         return;
136     }
137     d->m_continueCall = false;
138
139     if (flags & QPaintEngine::DirtyOpacity) {
140         d->m_alphaOpacity = (state.opacity() != 1.0f);
141     }
142
143     if (flags & QPaintEngine::DirtyBrush) {
144         if (state.brush().style() == Qt::NoBrush) {
145             d->m_advancedBrush = false;
146             d->m_alphaBrush = false;
147         } else {
148             d->m_advancedBrush = (state.brush().style() != Qt::SolidPattern);
149             d->m_alphaBrush = !state.brush().isOpaque();
150         }
151     }
152
153
154     d->m_hasalpha = d->m_alphaOpacity || d->m_alphaBrush || d->m_alphaPen;
155
156     if (d->m_picengine)
157         d->m_picengine->updateState(state);
158 }
159
160 void QAlphaPaintEngine::drawPath(const QPainterPath &path)
161 {
162     Q_D(QAlphaPaintEngine);
163
164     QRectF tr = d->addPenWidth(path);
165
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)
170         {
171             d->addAlphaRect(tr);
172         }
173         if (d->m_picengine)
174             d->m_picengine->drawPath(path);
175     } else {
176         d->m_continueCall = !d->fullyContained(tr);
177     }
178 }
179
180 void QAlphaPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
181 {
182     Q_D(QAlphaPaintEngine);
183
184     QPolygonF poly;
185     for (int i=0; i<pointCount; ++i)
186         poly.append(points[i]);
187
188     QPainterPath path;
189     path.addPolygon(poly);
190     QRectF tr = d->addPenWidth(path);
191
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)
196         {
197             d->addAlphaRect(tr);
198         }
199
200         if (d->m_picengine)
201             d->m_picengine->drawPolygon(points, pointCount, mode);
202     } else {
203         d->m_continueCall = !d->fullyContained(tr);
204     }
205 }
206
207 void QAlphaPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
208 {
209     Q_D(QAlphaPaintEngine);
210
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()) {
215             d->addAlphaRect(tr);
216         }
217
218         if (d->m_picengine)
219             d->m_picengine->drawPixmap(r, pm, sr);
220
221     } else {
222         d->m_continueCall = !d->fullyContained(tr);
223     }
224 }
225
226 void QAlphaPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
227 {
228     Q_D(QAlphaPaintEngine);
229
230     QRectF tr(p.x(), p.y() - textItem.ascent(), textItem.width() + 5, textItem.ascent() + textItem.descent() + 5);
231     tr = d->m_transform.mapRect(tr);
232
233     if (d->m_pass == 0) {
234         d->m_continueCall = false;
235         if (d->m_alphaPen || d->m_alphaOpacity || d->m_advancedPen) {
236             d->addAlphaRect(tr);
237         }
238         if (d->m_picengine) {
239             d->m_picengine->drawTextItem(p, textItem);
240         }
241     } else {
242         d->m_continueCall = !d->fullyContained(tr);
243     }
244 }
245
246 void QAlphaPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s)
247 {
248     Q_D(QAlphaPaintEngine);
249
250     QRectF brect = d->m_transform.mapRect(r);
251
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);
256         }
257         if (d->m_picengine)
258             d->m_picengine->drawTiledPixmap(r, pixmap, s);
259     } else {
260         d->m_continueCall = !d->fullyContained(brect);
261     }
262 }
263
264 QRegion QAlphaPaintEngine::alphaClipping() const
265 {
266     Q_D(const QAlphaPaintEngine);
267     return d->m_cliprgn;
268 }
269
270 bool QAlphaPaintEngine::continueCall() const
271 {
272     Q_D(const QAlphaPaintEngine);
273     return d->m_continueCall;
274 }
275
276 void QAlphaPaintEngine::flushAndInit(bool init)
277 {
278     Q_D(QAlphaPaintEngine);
279     Q_ASSERT(d->m_pass == 0);
280
281     if (d->m_pic) {
282         d->m_picpainter->end();
283
284         // set clip region
285         d->m_alphargn = d->m_alphargn.intersected(QRect(0, 0, d->m_pdev->width(), d->m_pdev->height()));
286
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);
292             rects.clear();
293             rects.append(br);
294         }
295
296         d->m_cliprgn = d->m_alphargn;
297
298         // now replay the QPicture
299         ++d->m_pass; // we are now doing pass #2
300
301         // reset states
302         gccaps = d->m_savedcaps;
303
304         painter()->save();
305         d->resetState(painter());
306
307         // make sure the output from QPicture is unscaled
308         QTransform mtx;
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);
313
314         d->m_cliprgn = QRegion();
315         d->resetState(painter());
316
317         // fill in the alpha images
318         for (int i=0; i<rects.size(); ++i)
319             d->drawAlphaImage(rects.at(i));
320
321         d->m_alphargn = QRegion();
322
323         painter()->restore();
324
325         --d->m_pass; // pass #2 finished
326
327         cleanUp();
328     }
329
330     if (init) {
331         gccaps = PaintEngineFeatures(AllFeatures & ~QPaintEngine::ObjectBoundingModeGradients);
332
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();
337
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();
348     }
349 }
350
351 void QAlphaPaintEngine::cleanUp()
352 {
353     Q_D(QAlphaPaintEngine);
354
355     delete d->m_picpainter;
356     delete d->m_pic;
357
358     d->m_picpainter = 0;
359     d->m_pic = 0;
360     d->m_picengine = 0;
361 }
362
363 QAlphaPaintEnginePrivate::QAlphaPaintEnginePrivate()
364     :   m_pass(0),
365         m_pic(0),
366         m_picengine(0),
367         m_picpainter(0),
368         m_hasalpha(false),
369         m_alphaPen(false),
370         m_alphaBrush(false),
371         m_alphaOpacity(false),
372         m_advancedPen(false),
373         m_advancedBrush(false),
374         m_complexTransform(false)
375 {
376
377 }
378
379 QAlphaPaintEnginePrivate::~QAlphaPaintEnginePrivate()
380 {
381     delete m_picpainter;
382     delete m_pic;
383 }
384
385 QRectF QAlphaPaintEnginePrivate::addPenWidth(const QPainterPath &path)
386 {
387     QPainterPath tmp = path;
388
389     if (m_pen.style() == Qt::NoPen)
390         return (path.controlPointRect() * m_transform).boundingRect();
391     if (m_pen.isCosmetic())
392         tmp = path * m_transform;
393
394     QPainterPathStroker stroker;
395     if (m_pen.widthF() == 0.0f)
396         stroker.setWidth(1.0);
397     else
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();
404
405     return (tmp.controlPointRect() * m_transform).boundingRect();
406 }
407
408 QRect QAlphaPaintEnginePrivate::toRect(const QRectF &rect) const
409 {
410     QRect r;
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));
415     return r;
416 }
417
418 void QAlphaPaintEnginePrivate::addAlphaRect(const QRectF &rect)
419 {
420     m_alphargn |= toRect(rect);
421 }
422
423 void QAlphaPaintEnginePrivate::drawAlphaImage(const QRectF &rect)
424 {
425     Q_Q(QAlphaPaintEngine);
426
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());
431
432     QTransform picscale;
433     picscale.scale(xscale, yscale);
434
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);
439     divw += 1;
440     divh += 1;
441
442     int incx = int(rect.width() / divw);
443     int incy = int(rect.height() / divh);
444
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;
448
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;
452
453             QSize imgsize((int)(width * xscale), (int)(height * yscale));
454             QImage img(imgsize, QImage::Format_RGB32);
455             img.fill(0xffffffff);
456
457             QPainter imgpainter(&img);
458             imgpainter.setTransform(picscale);
459             QPointF picpos(qreal(-xpos), qreal(-ypos));
460             imgpainter.drawPicture(picpos, *m_pic);
461             imgpainter.end();
462
463             q->painter()->setTransform(QTransform());
464             QRect r(xpos, ypos, width, height);
465             q->painter()->drawImage(r, img);
466         }
467     }
468 }
469
470 bool QAlphaPaintEnginePrivate::fullyContained(const QRectF &rect) const
471 {
472     QRegion r(toRect(rect));
473     return (m_cliprgn.intersected(r) == r);
474 }
475
476 void QAlphaPaintEnginePrivate::resetState(QPainter *p)
477 {
478     p->setPen(QPen());
479     p->setBrush(QBrush());
480     p->setBrushOrigin(0,0);
481     p->setBackground(QBrush());
482     p->setFont(QFont());
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);
491     p->setOpacity(1.0f);
492 }
493
494
495 QT_END_NAMESPACE
496
497 #endif // QT_NO_PRINTER