source: trunk/src/gui/painting/qpaintengine_alpha.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 14.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
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 "QtGui/qpicture.h"
50
51QT_BEGIN_NAMESPACE
52
53QAlphaPaintEngine::QAlphaPaintEngine(QAlphaPaintEnginePrivate &data, PaintEngineFeatures devcaps)
54 : QPaintEngine(data, devcaps)
55{
56
57}
58
59QAlphaPaintEngine::~QAlphaPaintEngine()
60{
61
62}
63
64bool QAlphaPaintEngine::begin(QPaintDevice *pdev)
65{
66 Q_D(QAlphaPaintEngine);
67
68 d->m_continueCall = true;
69 if (d->m_pass != 0) {
70 return true;
71 }
72
73 d->m_savedcaps = gccaps;
74 d->m_pdev = pdev;
75
76 d->m_alphaPen = false;
77 d->m_alphaBrush = false;
78 d->m_alphaOpacity = false;
79 d->m_hasalpha = false;
80 d->m_advancedPen = false;
81 d->m_advancedBrush = false;
82 d->m_complexTransform = false;
83 d->m_emulateProjectiveTransforms = false;
84
85 // clear alpha region
86 d->m_alphargn = QRegion();
87 d->m_cliprgn = QRegion();
88 d->m_pen = QPen();
89 d->m_transform = QTransform();
90
91 flushAndInit();
92
93 return true;
94}
95
96Q_GUI_EXPORT extern int qt_defaultDpiX();
97Q_GUI_EXPORT extern int qt_defaultDpiY();
98
99bool QAlphaPaintEngine::end()
100{
101 Q_D(QAlphaPaintEngine);
102
103 d->m_continueCall = true;
104 if (d->m_pass != 0) {
105 return true;
106 }
107
108 flushAndInit(false);
109 return true;
110}
111
112void QAlphaPaintEngine::updateState(const QPaintEngineState &state)
113{
114 Q_D(QAlphaPaintEngine);
115
116 DirtyFlags flags = state.state();
117 if (flags & QPaintEngine::DirtyTransform) {
118 d->m_transform = state.transform();
119 d->m_complexTransform = (d->m_transform.type() > QTransform::TxScale);
120 d->m_emulateProjectiveTransforms = !(d->m_savedcaps & QPaintEngine::PerspectiveTransform)
121 && !(d->m_savedcaps & QPaintEngine::AlphaBlend)
122 && (d->m_transform.type() >= QTransform::TxProject);
123 }
124 if (flags & QPaintEngine::DirtyPen) {
125 d->m_pen = state.pen();
126 if (d->m_pen.style() == Qt::NoPen) {
127 d->m_advancedPen = false;
128 d->m_alphaPen = false;
129 } else {
130 d->m_advancedPen = (d->m_pen.brush().style() != Qt::SolidPattern);
131 d->m_alphaPen = !d->m_pen.brush().isOpaque();
132 }
133 }
134
135 if (d->m_pass != 0) {
136 d->m_continueCall = true;
137 return;
138 }
139 d->m_continueCall = false;
140
141 if (flags & QPaintEngine::DirtyOpacity) {
142 d->m_alphaOpacity = (state.opacity() != 1.0f);
143 }
144
145 if (flags & QPaintEngine::DirtyBrush) {
146 if (state.brush().style() == Qt::NoBrush) {
147 d->m_advancedBrush = false;
148 d->m_alphaBrush = false;
149 } else {
150 d->m_advancedBrush = (state.brush().style() != Qt::SolidPattern);
151 d->m_alphaBrush = !state.brush().isOpaque();
152 }
153 }
154
155
156 d->m_hasalpha = d->m_alphaOpacity || d->m_alphaBrush || d->m_alphaPen;
157
158 if (d->m_picengine)
159 d->m_picengine->updateState(state);
160}
161
162void QAlphaPaintEngine::drawPath(const QPainterPath &path)
163{
164 Q_D(QAlphaPaintEngine);
165
166 QRectF tr = d->addPenWidth(path);
167
168 if (d->m_pass == 0) {
169 d->m_continueCall = false;
170 if (d->m_hasalpha || d->m_advancedPen || d->m_advancedBrush
171 || d->m_emulateProjectiveTransforms)
172 {
173 d->addAlphaRect(tr);
174 }
175 if (d->m_picengine)
176 d->m_picengine->drawPath(path);
177 } else {
178 d->m_continueCall = !d->fullyContained(tr);
179 }
180}
181
182void QAlphaPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
183{
184 Q_D(QAlphaPaintEngine);
185
186 QPolygonF poly;
187 for (int i=0; i<pointCount; ++i)
188 poly.append(points[i]);
189
190 QPainterPath path;
191 path.addPolygon(poly);
192 QRectF tr = d->addPenWidth(path);
193
194 if (d->m_pass == 0) {
195 d->m_continueCall = false;
196 if (d->m_hasalpha || d->m_advancedPen || d->m_advancedBrush
197 || d->m_emulateProjectiveTransforms)
198 {
199 d->addAlphaRect(tr);
200 }
201
202 if (d->m_picengine)
203 d->m_picengine->drawPolygon(points, pointCount, mode);
204 } else {
205 d->m_continueCall = !d->fullyContained(tr);
206 }
207}
208
209void QAlphaPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
210{
211 Q_D(QAlphaPaintEngine);
212
213 QRectF tr = d->m_transform.mapRect(r);
214 if (d->m_pass == 0) {
215 d->m_continueCall = false;
216 if (pm.hasAlpha() || d->m_alphaOpacity || d->m_complexTransform || pm.isQBitmap()) {
217 d->addAlphaRect(tr);
218 }
219
220 if (d->m_picengine)
221 d->m_picengine->drawPixmap(r, pm, sr);
222
223 } else {
224 d->m_continueCall = !d->fullyContained(tr);
225 }
226}
227
228void QAlphaPaintEngine::drawImage(const QRectF &r, const QImage &image, const QRectF &sr)
229{
230 Q_D(QAlphaPaintEngine);
231
232 QRectF tr = d->m_transform.mapRect(r);
233 if (d->m_pass == 0) {
234 d->m_continueCall = false;
235 if (image.hasAlphaChannel() || d->m_alphaOpacity || d->m_complexTransform) {
236 d->addAlphaRect(tr);
237 }
238
239 if (d->m_picengine)
240 d->m_picengine->drawImage(r, image, sr);
241
242 } else {
243 d->m_continueCall = !d->fullyContained(tr);
244 }
245}
246
247void QAlphaPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
248{
249 Q_D(QAlphaPaintEngine);
250
251 QRectF tr(p.x(), p.y() - textItem.ascent(), textItem.width() + 5, textItem.ascent() + textItem.descent() + 5);
252 tr = d->m_transform.mapRect(tr);
253
254 if (d->m_pass == 0) {
255 d->m_continueCall = false;
256 if (d->m_alphaPen || d->m_alphaOpacity || d->m_advancedPen) {
257 d->addAlphaRect(tr);
258 }
259 if (d->m_picengine) {
260 d->m_picengine->drawTextItem(p, textItem);
261 }
262 } else {
263 d->m_continueCall = !d->fullyContained(tr);
264 }
265}
266
267void QAlphaPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s)
268{
269 Q_D(QAlphaPaintEngine);
270
271 QRectF brect = d->m_transform.mapRect(r);
272
273 if (d->m_pass == 0) {
274 d->m_continueCall = false;
275 if (pixmap.hasAlpha() || d->m_alphaOpacity || d->m_complexTransform || pixmap.isQBitmap()) {
276 d->addAlphaRect(brect);
277 }
278 if (d->m_picengine)
279 d->m_picengine->drawTiledPixmap(r, pixmap, s);
280 } else {
281 d->m_continueCall = !d->fullyContained(brect);
282 }
283}
284
285QRegion QAlphaPaintEngine::alphaClipping() const
286{
287 Q_D(const QAlphaPaintEngine);
288 return d->m_cliprgn;
289}
290
291bool QAlphaPaintEngine::continueCall() const
292{
293 Q_D(const QAlphaPaintEngine);
294 return d->m_continueCall;
295}
296
297void QAlphaPaintEngine::flushAndInit(bool init)
298{
299 Q_D(QAlphaPaintEngine);
300 Q_ASSERT(d->m_pass == 0);
301
302 if (d->m_pic) {
303 d->m_picpainter->end();
304
305 // set clip region
306 d->m_alphargn = d->m_alphargn.intersected(QRect(0, 0, d->m_pdev->width(), d->m_pdev->height()));
307
308 // just use the bounding rect if it's a complex region..
309 QVector<QRect> rects = d->m_alphargn.rects();
310 if (rects.size() > 10) {
311 QRect br = d->m_alphargn.boundingRect();
312 d->m_alphargn = QRegion(br);
313 rects.clear();
314 rects.append(br);
315 }
316
317 d->m_cliprgn = d->m_alphargn;
318
319 // now replay the QPicture
320 ++d->m_pass; // we are now doing pass #2
321
322 // reset states
323 gccaps = d->m_savedcaps;
324
325 painter()->save();
326 d->resetState(painter());
327
328 // make sure the output from QPicture is unscaled
329 QTransform mtx;
330 mtx.scale(1.0f / (qreal(d->m_pdev->logicalDpiX()) / qreal(qt_defaultDpiX())),
331 1.0f / (qreal(d->m_pdev->logicalDpiY()) / qreal(qt_defaultDpiY())));
332 painter()->setTransform(mtx);
333 painter()->drawPicture(0, 0, *d->m_pic);
334
335 d->m_cliprgn = QRegion();
336 d->resetState(painter());
337
338 // fill in the alpha images
339 for (int i=0; i<rects.size(); ++i)
340 d->drawAlphaImage(rects.at(i));
341
342 d->m_alphargn = QRegion();
343
344 painter()->restore();
345
346 --d->m_pass; // pass #2 finished
347
348 cleanUp();
349 }
350
351 if (init) {
352 gccaps = PaintEngineFeatures(AllFeatures & ~QPaintEngine::ObjectBoundingModeGradients);
353
354 d->m_pic = new QPicture();
355 d->m_pic->d_ptr->in_memory_only = true;
356 d->m_picpainter = new QPainter(d->m_pic);
357 d->m_picengine = d->m_picpainter->paintEngine();
358
359 // When newPage() is called and the m_picpainter is recreated
360 // we have to copy the current state of the original printer
361 // painter back to the m_picpainter
362 d->m_picpainter->setPen(painter()->pen());
363 d->m_picpainter->setBrush(painter()->brush());
364 d->m_picpainter->setBrushOrigin(painter()->brushOrigin());
365 d->m_picpainter->setFont(painter()->font());
366 d->m_picpainter->setOpacity(painter()->opacity());
367 d->m_picpainter->setTransform(painter()->combinedTransform());
368 d->m_picengine->syncState();
369 }
370}
371
372void QAlphaPaintEngine::cleanUp()
373{
374 Q_D(QAlphaPaintEngine);
375
376 delete d->m_picpainter;
377 delete d->m_pic;
378
379 d->m_picpainter = 0;
380 d->m_pic = 0;
381 d->m_picengine = 0;
382}
383
384QAlphaPaintEnginePrivate::QAlphaPaintEnginePrivate()
385 : m_pass(0),
386 m_pic(0),
387 m_picengine(0),
388 m_picpainter(0),
389 m_hasalpha(false),
390 m_alphaPen(false),
391 m_alphaBrush(false),
392 m_alphaOpacity(false),
393 m_advancedPen(false),
394 m_advancedBrush(false),
395 m_complexTransform(false)
396{
397
398}
399
400QAlphaPaintEnginePrivate::~QAlphaPaintEnginePrivate()
401{
402 delete m_picpainter;
403 delete m_pic;
404}
405
406QRectF QAlphaPaintEnginePrivate::addPenWidth(const QPainterPath &path)
407{
408 QPainterPath tmp = path;
409
410 if (m_pen.style() == Qt::NoPen)
411 return (path.controlPointRect() * m_transform).boundingRect();
412 if (m_pen.isCosmetic())
413 tmp = path * m_transform;
414
415 QPainterPathStroker stroker;
416 if (m_pen.widthF() == 0.0f)
417 stroker.setWidth(1.0);
418 else
419 stroker.setWidth(m_pen.widthF());
420 stroker.setJoinStyle(m_pen.joinStyle());
421 stroker.setCapStyle(m_pen.capStyle());
422 tmp = stroker.createStroke(tmp);
423 if (m_pen.isCosmetic())
424 return tmp.controlPointRect();
425
426 return (tmp.controlPointRect() * m_transform).boundingRect();
427}
428
429QRect QAlphaPaintEnginePrivate::toRect(const QRectF &rect) const
430{
431 QRect r;
432 r.setLeft(int(rect.left()));
433 r.setTop(int(rect.top()));
434 r.setRight(int(rect.right() + 1));
435 r.setBottom(int(rect.bottom() + 1));
436 return r;
437}
438
439void QAlphaPaintEnginePrivate::addAlphaRect(const QRectF &rect)
440{
441 m_alphargn |= toRect(rect);
442}
443
444void QAlphaPaintEnginePrivate::drawAlphaImage(const QRectF &rect)
445{
446 Q_Q(QAlphaPaintEngine);
447
448 qreal dpiX = qMax(m_pdev->logicalDpiX(), 300);
449 qreal dpiY = qMax(m_pdev->logicalDpiY(), 300);
450 qreal xscale = (dpiX / m_pdev->logicalDpiX());
451 qreal yscale = (dpiY / m_pdev->logicalDpiY());
452
453 QTransform picscale;
454 picscale.scale(xscale, yscale);
455
456 const int tileSize = 2048;
457 QSize size((int(rect.width() * xscale)), int(rect.height() * yscale));
458 int divw = (size.width() / tileSize);
459 int divh = (size.height() / tileSize);
460 divw += 1;
461 divh += 1;
462
463 int incx = int(rect.width() / divw);
464 int incy = int(rect.height() / divh);
465
466 for (int y=0; y<divh; ++y) {
467 int ypos = int((incy * y) + rect.y());
468 int height = int((y == (divh - 1)) ? (rect.height() - (incy * y)) : incy) + 1;
469
470 for (int x=0; x<divw; ++x) {
471 int xpos = int((incx * x) + rect.x());
472 int width = int((x == (divw - 1)) ? (rect.width() - (incx * x)) : incx) + 1;
473
474 QSize imgsize((int)(width * xscale), (int)(height * yscale));
475 QImage img(imgsize, QImage::Format_RGB32);
476 img.fill(0xffffffff);
477
478 QPainter imgpainter(&img);
479 imgpainter.setTransform(picscale);
480 QPointF picpos(qreal(-xpos), qreal(-ypos));
481 imgpainter.drawPicture(picpos, *m_pic);
482 imgpainter.end();
483
484 q->painter()->setTransform(QTransform());
485 QRect r(xpos, ypos, width, height);
486 q->painter()->drawImage(r, img);
487 }
488 }
489}
490
491bool QAlphaPaintEnginePrivate::fullyContained(const QRectF &rect) const
492{
493 QRegion r(toRect(rect));
494 return (m_cliprgn.intersected(r) == r);
495}
496
497void QAlphaPaintEnginePrivate::resetState(QPainter *p)
498{
499 p->setPen(QPen());
500 p->setBrush(QBrush());
501 p->setBrushOrigin(0,0);
502 p->setBackground(QBrush());
503 p->setFont(QFont());
504 p->setTransform(QTransform());
505 // The view transform is already recorded and included in the
506 // picture we're about to replay. If we don't turn if off,
507 // the view matrix will be applied twice.
508 p->setViewTransformEnabled(false);
509 p->setClipRegion(QRegion(), Qt::NoClip);
510 p->setClipPath(QPainterPath(), Qt::NoClip);
511 p->setClipping(false);
512 p->setOpacity(1.0f);
513}
514
515
516QT_END_NAMESPACE
517
518#endif // QT_NO_PRINTER
Note: See TracBrowser for help on using the repository browser.