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