1 /****************************************************************************
3 ** Copyright (C) 2010 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 QtDeclarative 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 ****************************************************************************/
42 #include "qsgcontext2dcommandbuffer_p.h"
43 #include "qsgcanvasitem_p.h"
44 #include "qdeclarative.h"
45 #include <QtGui/QApplication>
46 #include <QtCore/QMutex>
48 #define HAS_SHADOW(offsetX, offsetY, blur, color) (color.isValid() && color.alpha() && (blur || offsetX || offsetY))
49 static QImage makeShadowImage(const QImage& image, qreal offsetX, qreal offsetY, qreal blur, const QColor& color)
51 QImage shadowImg(image.width() + blur * 2 + qAbs(offsetX),
52 image.height() + blur *2 + qAbs(offsetY),
53 QImage::Format_ARGB32);
55 QPainter tmpPainter(&shadowImg);
56 tmpPainter.setCompositionMode(QPainter::CompositionMode_Source);
57 qreal shadowX = offsetX > 0? offsetX : 0;
58 qreal shadowY = offsetY > 0? offsetY : 0;
60 tmpPainter.drawImage(shadowX, shadowY, image);
63 // blur the alpha channel
65 QImage blurred(shadowImg.size(), QImage::Format_ARGB32);
67 QPainter blurPainter(&blurred);
68 qt_blurImage(&blurPainter, shadowImg, blur, true, false);
73 // blacken the image with shadow color...
74 tmpPainter.begin(&shadowImg);
75 tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
76 tmpPainter.fillRect(shadowImg.rect(), color);
81 static void fillRectShadow(QPainter* p, QRectF shadowRect, qreal offsetX, qreal offsetY, qreal blur, const QColor& color)
83 QRectF r = shadowRect;
86 QImage shadowImage(r.size().width() + 1, r.size().height() + 1, QImage::Format_ARGB32);
88 tp.begin(&shadowImage);
89 tp.fillRect(r, p->brush());
91 shadowImage = makeShadowImage(shadowImage, offsetX, offsetY, blur, color);
93 qreal dx = shadowRect.left() + (offsetX < 0? offsetX:0);
94 qreal dy = shadowRect.top() + (offsetY < 0? offsetY:0);
96 p->drawImage(dx, dy, shadowImage);
97 p->fillRect(shadowRect, p->brush());
100 static void fillShadowPath(QPainter* p, const QPainterPath& path, qreal offsetX, qreal offsetY, qreal blur, const QColor& color)
102 QRectF r = path.boundingRect();
103 QImage img(r.size().width() + r.left() + 1,
104 r.size().height() + r.top() + 1,
105 QImage::Format_ARGB32);
108 tp.fillPath(path.translated(0, 0), p->brush());
111 QImage shadowImage = makeShadowImage(img, offsetX, offsetY, blur, color);
112 qreal dx = r.left() + (offsetX < 0? offsetX:0);
113 qreal dy = r.top() + (offsetY < 0? offsetY:0);
115 p->drawImage(dx, dy, shadowImage);
116 p->fillPath(path, p->brush());
119 static void strokeShadowPath(QPainter* p, const QPainterPath& path, qreal offsetX, qreal offsetY, qreal blur, const QColor& color)
121 QRectF r = path.boundingRect();
122 QImage img(r.size().width() + r.left() + 1,
123 r.size().height() + r.top() + 1,
124 QImage::Format_ARGB32);
127 tp.strokePath(path, p->pen());
130 QImage shadowImage = makeShadowImage(img, offsetX, offsetY, blur, color);
131 qreal dx = r.left() + (offsetX < 0? offsetX:0);
132 qreal dy = r.top() + (offsetY < 0? offsetY:0);
133 p->drawImage(dx, dy, shadowImage);
134 p->strokePath(path, p->pen());
137 QPen QSGContext2DCommandBuffer::makePen(QSGContext2D::State state)
140 pen.setWidthF(state.lineWidth);
141 pen.setCapStyle(state.lineCap);
142 pen.setJoinStyle(state.lineJoin);
143 pen.setMiterLimit(state.miterLimit);
144 pen.setBrush(state.strokeStyle);
148 void QSGContext2DCommandBuffer::setPainterState(QPainter* p, QSGContext2D::State state, const QPen& pen)
150 p->setTransform(state.matrix * p->transform());
155 if (state.fillStyle != p->brush())
156 p->setBrush(state.fillStyle);
158 if (state.font != p->font())
159 p->setFont(state.font);
161 if (state.globalAlpha != p->opacity()) {
162 p->setOpacity(state.globalAlpha);
165 if (state.globalCompositeOperation != p->compositionMode())
166 p->setCompositionMode(state.globalCompositeOperation);
169 QSGContext2D::State QSGContext2DCommandBuffer::replay(QPainter* p, QSGContext2D::State state)
176 QTransform originMatrix = p->transform();
178 QPen pen = makePen(state);
179 setPainterState(p, state, pen);
182 QSGContext2D::PaintCommand cmd = takeNextCommand();
184 case QSGContext2D::UpdateMatrix:
186 state.matrix = takeMatrix();
187 p->setTransform(state.matrix * originMatrix);
190 case QSGContext2D::ClearRect:
192 p->eraseRect(takeRect());
195 case QSGContext2D::FillRect:
197 QRectF r = takeRect();
198 if (HAS_SHADOW(state.shadowOffsetX, state.shadowOffsetY, state.shadowBlur, state.shadowColor))
199 fillRectShadow(p, r, state.shadowOffsetX, state.shadowOffsetY, state.shadowBlur, state.shadowColor);
201 p->fillRect(r, p->brush());
204 case QSGContext2D::ShadowColor:
206 state.shadowColor = takeColor();
209 case QSGContext2D::ShadowBlur:
211 state.shadowBlur = takeShadowBlur();
214 case QSGContext2D::ShadowOffsetX:
216 state.shadowOffsetX = takeShadowOffsetX();
219 case QSGContext2D::ShadowOffsetY:
221 state.shadowOffsetY = takeShadowOffsetY();
224 case QSGContext2D::FillStyle:
226 state.fillStyle = takeFillStyle();
227 p->setBrush(state.fillStyle);
230 case QSGContext2D::StrokeStyle:
232 state.strokeStyle = takeStrokeStyle();
233 pen.setBrush(state.strokeStyle);
237 case QSGContext2D::LineWidth:
239 state.lineWidth = takeLineWidth();
240 pen.setWidth(state.lineWidth);
244 case QSGContext2D::LineCap:
246 state.lineCap = takeLineCap();
247 pen.setCapStyle(state.lineCap);
251 case QSGContext2D::LineJoin:
253 state.lineJoin = takeLineJoin();
254 pen.setJoinStyle(state.lineJoin);
258 case QSGContext2D::MiterLimit:
260 state.miterLimit = takeMiterLimit();
261 pen.setMiterLimit(state.miterLimit);
265 case QSGContext2D::TextAlign:
266 case QSGContext2D::TextBaseline:
268 case QSGContext2D::Fill:
270 if (HAS_SHADOW(state.shadowOffsetX, state.shadowOffsetY, state.shadowBlur, state.shadowColor))
271 fillShadowPath(p,takePath(), state.shadowOffsetX, state.shadowOffsetY, state.shadowBlur, state.shadowColor);
273 p->fillPath(takePath(), p->brush());
276 case QSGContext2D::Stroke:
278 if (HAS_SHADOW(state.shadowOffsetX, state.shadowOffsetY, state.shadowBlur, state.shadowColor))
279 strokeShadowPath(p,takePath(), state.shadowOffsetX, state.shadowOffsetY, state.shadowBlur, state.shadowColor);
281 p->strokePath(takePath(), p->pen());
284 case QSGContext2D::Clip:
286 QPainterPath clipPath = takePath();
287 clipPath.closeSubpath();
288 state.clipPath = state.clipPath.intersected(clipPath);
289 if (!p->clipPath().isEmpty())
290 clipPath = clipPath.intersected(p->clipPath());
291 p->setClipping(true);
292 p->setClipPath(clipPath);
295 case QSGContext2D::UpdateBrush:
297 state.fillStyle = takeBrush();
298 p->setBrush(state.fillStyle);
302 case QSGContext2D::GlobalAlpha:
304 state.globalAlpha = takeGlobalAlpha();
305 p->setOpacity(state.globalAlpha);
308 case QSGContext2D::GlobalCompositeOperation:
310 state.globalCompositeOperation = takeGlobalCompositeOperation();
311 p->setCompositionMode(state.globalCompositeOperation);
314 case QSGContext2D::DrawImage:
316 qreal sx = takeReal();
317 qreal sy = takeReal();
318 qreal sw = takeReal();
319 qreal sh = takeReal();
320 qreal dx = takeReal();
321 qreal dy = takeReal();
322 qreal dw = takeReal();
323 qreal dh = takeReal();
324 QImage image = takeImage();
326 if (!image.isNull()) {
327 if (sw == -1 || sh == -1) {
331 if (sx != 0 || sy != 0 || sw != image.width() || sh != image.height())
332 image = image.copy(sx, sy, sw, sh);
334 image = image.scaled(dw, dh);
336 if (HAS_SHADOW(state.shadowOffsetX, state.shadowOffsetY, state.shadowBlur, state.shadowColor)) {
337 QImage shadow = makeShadowImage(image, state.shadowOffsetX, state.shadowOffsetY, state.shadowBlur, state.shadowColor);
338 qreal shadow_dx = dx + (state.shadowOffsetX < 0? state.shadowOffsetY:0);
339 qreal shadow_dy = dy + (state.shadowOffsetX < 0? state.shadowOffsetY:0);
340 p->drawImage(shadow_dx, shadow_dy, shadow);
342 p->drawImage(dx, dy, image);
346 case QSGContext2D::GetImageData:
360 QSGContext2DCommandBuffer::QSGContext2DCommandBuffer()
373 QSGContext2DCommandBuffer::~QSGContext2DCommandBuffer()
377 void QSGContext2DCommandBuffer::clear()
390 void QSGContext2DCommandBuffer::reset()