127 { |
130 { |
128 // Double the height of the rectangle but take also the offset into account. |
131 // Double the height of the rectangle but take also the offset into account. |
129 Q_D(const HbVgReflectionEffect); |
132 Q_D(const HbVgReflectionEffect); |
130 QRectF r(rect); |
133 QRectF r(rect); |
131 QPointF mappedOffset = d->mapOffset(d->offset); |
134 QPointF mappedOffset = d->mapOffset(d->offset); |
132 qreal rotationAngle = d->mainWindowRotation(); |
135 qreal rotationAngle = d->mainWindowRotation(); |
133 |
136 |
134 if (rotationAngle == 0) |
137 if (rotationAngle == 0) { |
135 r.adjust(0, 0, 0, r.height()); |
138 r.adjust(0, 0, 0, r.height()); |
136 else if (rotationAngle == 90 || rotationAngle == -270) |
139 } else if (rotationAngle == 90 || rotationAngle == -270) { |
137 r.adjust(-r.width(), 0, 0, 0); |
140 r.adjust(-r.width(), 0, 0, 0); |
138 else if (rotationAngle == -90 || rotationAngle == 270) |
141 } else if (rotationAngle == -90 || rotationAngle == 270) { |
139 r.adjust(0, 0, r.width(), 0); |
142 r.adjust(0, 0, r.width(), 0); |
140 |
143 } |
|
144 |
141 qreal x1 = qMin(r.left(), r.left() + mappedOffset.x()); |
145 qreal x1 = qMin(r.left(), r.left() + mappedOffset.x()); |
142 qreal y1 = qMin(r.top(), r.top() + mappedOffset.y()); |
146 qreal y1 = qMin(r.top(), r.top() + mappedOffset.y()); |
143 qreal x2 = qMax(r.right(), r.right() + mappedOffset.x()); |
147 qreal x2 = qMax(r.right(), r.right() + mappedOffset.x()); |
144 qreal y2 = qMax(r.bottom(), r.bottom() + mappedOffset.y()); |
148 qreal y2 = qMax(r.bottom(), r.bottom() + mappedOffset.y()); |
145 |
149 |
146 return QRectF(x1, y1, x2 - x1 + 1, y2 - y1 + 1); |
150 return QRectF(x1, y1, x2 - x1 + 1, y2 - y1 + 1); |
147 } |
151 } |
148 |
152 |
149 void HbVgReflectionEffect::performEffect(QPainter *painter, |
153 void HbVgReflectionEffect::performEffect(QPainter *painter, |
150 const QPointF &offset, |
154 const QPointF &offset, |
151 const QVariant &vgImage, |
155 const QVariant &vgImage, |
152 const QSize &vgImageSize) |
156 const QSize &vgImageSize) |
153 { |
157 { |
154 #ifdef HB_EFFECTS_OPENVG |
158 #ifdef HB_EFFECTS_OPENVG |
155 Q_D(HbVgReflectionEffect); |
159 Q_D(HbVgReflectionEffect); |
156 |
160 |
157 if (d->hints & ForceFrameHint) { |
161 if (d->hints & ForceFrameHint) { |
160 painter->restore(); |
164 painter->restore(); |
161 } |
165 } |
162 |
166 |
163 QPaintDevice *pdev = painter->device(); |
167 QPaintDevice *pdev = painter->device(); |
164 QRectF rectWithChildren = d->deviceRectForSource( |
168 QRectF rectWithChildren = d->deviceRectForSource( |
165 HbVgFrameEffectPrivate::IncludeChildren, |
169 HbVgFrameEffectPrivate::IncludeChildren, |
166 pdev); |
170 pdev); |
167 QRectF rectWithoutChildren = d->deviceRectForSource( |
171 QRectF rectWithoutChildren = d->deviceRectForSource( |
168 HbVgFrameEffectPrivate::ExcludeChildren, |
172 HbVgFrameEffectPrivate::ExcludeChildren, |
169 pdev); |
173 pdev); |
170 VGImage srcImage = vgImage.value<VGImage>(); |
174 VGImage srcImage = vgImage.value<VGImage>(); |
171 VGImage dstImage = d->ensurePixmap(&d->dstPixmap, vgImageSize); |
175 VGImage dstImage = d->ensurePixmap(&d->dstPixmap, vgImageSize); |
172 |
176 |
173 // Draw the source pixmap using the painter, this will also set up the |
177 // Draw the source pixmap using the painter, this will also set up the |
174 // IMAGE_USER_TO_SURFACE matrix. |
178 // IMAGE_USER_TO_SURFACE matrix. |
175 painter->drawPixmap(offset, d->srcPixmap); |
179 painter->drawPixmap(offset, d->srcPixmap); |
176 |
180 |
177 // Prepare the mirrored image. |
181 // Prepare the mirrored image. |
178 qreal rotationAngle = d->mainWindowRotation(); |
182 qreal rotationAngle = d->mainWindowRotation(); |
179 qreal absRotationAngle = qAbs(rotationAngle); |
183 qreal absRotationAngle = qAbs(rotationAngle); |
180 |
184 |
181 VGfloat m[9]; |
185 VGfloat m[9]; |
182 vgGetMatrix(m); |
186 vgGetMatrix(m); |
183 vgLoadIdentity(); |
187 vgLoadIdentity(); |
184 if (absRotationAngle == 0) |
188 if (absRotationAngle == 0) { |
185 m[4] *= -1.0f; |
189 m[4] *= -1.0f; |
186 else if (absRotationAngle == 90 || absRotationAngle == 270) |
190 } else if (absRotationAngle == 90 || absRotationAngle == 270) { |
187 m[0] *= -1.0f; |
191 m[0] *= -1.0f; |
|
192 } |
188 vgMultMatrix(m); |
193 vgMultMatrix(m); |
189 |
194 |
190 // Must move the mirrored image to have it on top of the original and then down |
195 // Must move the mirrored image to have it on top of the original and then down |
191 // again to have it below in portrait-mode. Rotation angles -90 or 270 causes image to be moved to right, |
196 // again to have it below in portrait-mode. Rotation angles -90 or 270 causes image to be moved to right, |
192 // and in rotation angles -90 and 270, image is in correct place initially. |
197 // and in rotation angles -90 and 270, image is in correct place initially. |
193 // Try to take the exclude-children hint into account when performing the second move. |
198 // Try to take the exclude-children hint into account when performing the second move. |
194 |
199 |
195 VGfloat trans; |
200 VGfloat trans; |
196 if (absRotationAngle == 0) { |
201 if (absRotationAngle == 0) { |
197 if (d->hints & ExcludeChildrenHint) |
202 if (d->hints & ExcludeChildrenHint) { |
198 trans = -rectWithChildren.height() - rectWithoutChildren.height(); |
203 trans = -rectWithChildren.height() - rectWithoutChildren.height(); |
199 else |
204 } else { |
200 trans = -2.0f * rectWithChildren.height(); |
205 trans = -2.0f * rectWithChildren.height(); |
201 |
206 } |
|
207 |
202 vgTranslate(0.0f, trans); |
208 vgTranslate(0.0f, trans); |
203 } |
209 } else if (absRotationAngle == 90 || absRotationAngle == 270) { |
204 else if (absRotationAngle == 90 || absRotationAngle == 270) { |
210 if (d->hints & ExcludeChildrenHint) { |
205 if (d->hints & ExcludeChildrenHint) |
|
206 trans = -rectWithChildren.width() - rectWithoutChildren.width(); |
211 trans = -rectWithChildren.width() - rectWithoutChildren.width(); |
207 else |
212 } else { |
208 trans = -2.0f * rectWithChildren.width(); |
213 trans = -2.0f * rectWithChildren.width(); |
209 |
214 } |
|
215 |
210 vgTranslate(trans, 0.0f); |
216 vgTranslate(trans, 0.0f); |
211 } |
217 } |
212 |
218 |
213 // Apply the additional offset. Note: down = minus, right = plus. |
219 // Apply the additional offset. Note: down = minus, right = plus. |
214 QPointF mappedOffset = d->mapOffset(d->offset); |
220 QPointF mappedOffset = d->mapOffset(d->offset); |
215 VGfloat ox = (VGfloat) mappedOffset.x(); |
221 VGfloat ox = (VGfloat) mappedOffset.x(); |
216 VGfloat oy = (VGfloat) mappedOffset.y(); |
222 VGfloat oy = (VGfloat) mappedOffset.y(); |
217 |
223 |
218 if (rotationAngle == 0) |
224 if (rotationAngle == 0) { |
219 vgTranslate(ox, -oy); |
225 vgTranslate(ox, -oy); |
220 else if (rotationAngle == 90 || rotationAngle == -270) |
226 } else if (rotationAngle == 90 || rotationAngle == -270) { |
221 vgTranslate(-ox, oy); |
227 vgTranslate(-ox, oy); |
222 else if (rotationAngle == -90 || rotationAngle == 270) |
228 } else if (rotationAngle == -90 || rotationAngle == 270) { |
223 vgTranslate(-ox, oy); |
229 vgTranslate(-ox, oy); |
224 |
230 } |
|
231 |
225 // Apply the opacity and the color. When no color was set and the opacity is 1, the |
232 // Apply the opacity and the color. When no color was set and the opacity is 1, the |
226 // source image will be used as it is. This is the only place where we can try to use |
233 // source image will be used as it is. This is the only place where we can try to use |
227 // the pixmap cache. |
234 // the pixmap cache. |
228 VGImage imgToDraw = srcImage; |
235 VGImage imgToDraw = srcImage; |
229 QPixmap cachedPm = cached(vgImageSize); |
236 QPixmap cachedPm = cached(vgImageSize); |
230 if (cachedPm.isNull()) { |
237 if (cachedPm.isNull()) { |
231 VGImage tmpImage = VG_INVALID_HANDLE; |
238 VGImage tmpImage = VG_INVALID_HANDLE; |
232 if (d->color.isValid()) { |
239 if (d->color.isValid()) { |
233 // Perform a colorize effect (ignore the opacity here because it must be set for |
240 // Perform a colorize effect (ignore the opacity here because it must be set for |
234 // the full image, not just the color overlay). |
241 // the full image, not just the color overlay). |
235 tmpImage = d->ensurePixmap(&d->tmpPixmap, vgImageSize); |
242 tmpImage = d->ensurePixmap(&d->tmpPixmap, vgImageSize); |
240 } |
247 } |
241 qreal opacity = clamp(d->opacity, 0.0f, 1.0f); |
248 qreal opacity = clamp(d->opacity, 0.0f, 1.0f); |
242 if (d->opacity < 1.0f - HBVG_EPSILON) { |
249 if (d->opacity < 1.0f - HBVG_EPSILON) { |
243 // Apply the opacity, i.e. modify the alpha channel. |
250 // Apply the opacity, i.e. modify the alpha channel. |
244 if (d->paramsChanged) { |
251 if (d->paramsChanged) { |
245 for (int i = 0; i < 256; ++i) |
252 for (int i = 0; i < 256; ++i) { |
246 d->alphaLUT[i] = (VGubyte) (i * opacity); |
253 d->alphaLUT[i] = (VGubyte)(i * opacity); |
|
254 } |
247 } |
255 } |
248 vgLookup(dstImage, imgToDraw, |
256 vgLookup(dstImage, imgToDraw, |
249 identityLUT, identityLUT, identityLUT, d->alphaLUT, |
257 identityLUT, identityLUT, identityLUT, d->alphaLUT, |
250 VG_TRUE, VG_FALSE); |
258 VG_TRUE, VG_FALSE); |
251 imgToDraw = dstImage; |
259 imgToDraw = dstImage; |
252 } |
260 } |
253 // If colorize and/or opacity was used then try to cache the result. |
261 // If colorize and/or opacity was used then try to cache the result. |
254 if (imgToDraw == tmpImage) |
262 if (imgToDraw == tmpImage) { |
255 tryCache(d->tmpPixmap); |
263 tryCache(d->tmpPixmap); |
256 else if (imgToDraw == dstImage) |
264 } else if (imgToDraw == dstImage) { |
257 tryCache(d->dstPixmap); |
265 tryCache(d->dstPixmap); |
|
266 } |
258 } else { |
267 } else { |
259 imgToDraw = qPixmapToVGImage(cachedPm); |
268 imgToDraw = qPixmapToVGImage(cachedPm); |
260 } |
269 } |
261 |
270 |
262 // Fade out the lower part of the mirrored image. Skip this if 'fade' is 0, i.e. there |
271 // Fade out the lower part of the mirrored image. Skip this if 'fade' is 0, i.e. there |
287 } |
296 } |
288 |
297 |
289 // Set up the linear gradient based on the (transformed) size of the source. |
298 // Set up the linear gradient based on the (transformed) size of the source. |
290 VGfloat sw = (VGfloat) rectWithChildren.width(); |
299 VGfloat sw = (VGfloat) rectWithChildren.width(); |
291 VGfloat sh = (VGfloat) rectWithChildren.height(); |
300 VGfloat sh = (VGfloat) rectWithChildren.height(); |
292 // must be bottom-up to get the proper effect |
301 // must be bottom-up to get the proper effect |
293 if (rotationAngle == 0) { |
302 if (absRotationAngle == 0) { |
294 VGfloat grad[] = { sw / 2.0f, sh, |
303 VGfloat grad[] = { sw / 2.0f, sh, |
295 sw / 2.0f, 0.0f }; |
304 sw / 2.0f, 0.0f |
|
305 }; |
296 vgSetParameterfv(d->fadePaint, VG_PAINT_LINEAR_GRADIENT, 4, grad); |
306 vgSetParameterfv(d->fadePaint, VG_PAINT_LINEAR_GRADIENT, 4, grad); |
297 } |
307 } else if (absRotationAngle == 90 || absRotationAngle == 270) { |
298 else if (rotationAngle == -90 || rotationAngle == 270){ |
|
299 VGfloat grad[] = { sw, sh / 2.0f, |
308 VGfloat grad[] = { sw, sh / 2.0f, |
300 0.0f, sh / 2.0f }; |
309 0.0f, sh / 2.0f |
|
310 }; |
301 vgSetParameterfv(d->fadePaint, VG_PAINT_LINEAR_GRADIENT, 4, grad); |
311 vgSetParameterfv(d->fadePaint, VG_PAINT_LINEAR_GRADIENT, 4, grad); |
302 } |
312 } |
303 else if (rotationAngle == 90 || rotationAngle == -270){ |
|
304 VGfloat grad[] = { 0.0f, sh / 2.0f, |
|
305 sw, sh / 2.0f }; |
|
306 vgSetParameterfv(d->fadePaint, VG_PAINT_LINEAR_GRADIENT, 4, grad); |
|
307 } |
|
308 |
313 |
309 // Draw the mirrored image by using the paint to get a gradual fade-out effect. |
314 // Draw the mirrored image by using the paint to get a gradual fade-out effect. |
310 vgSeti(VG_MATRIX_MODE, VG_MATRIX_FILL_PAINT_TO_USER); |
315 vgSeti(VG_MATRIX_MODE, VG_MATRIX_FILL_PAINT_TO_USER); |
311 vgLoadIdentity(); |
316 vgLoadIdentity(); |
312 vgSetPaint(d->fadePaint, VG_FILL_PATH); |
317 vgSetPaint(d->fadePaint, VG_FILL_PATH); |