|
1 /******************************************************************************* |
|
2 * Copyright (c) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. This program and the accompanying materials |
|
4 * are made available under the terms of the Eclipse Public License v1.0 |
|
5 * which accompanies this distribution, and is available at |
|
6 * http://www.eclipse.org/legal/epl-v10.html |
|
7 * |
|
8 * Contributors: |
|
9 * Nokia Corporation - initial API and implementation |
|
10 *******************************************************************************/ |
|
11 |
|
12 //#include <QtOpenGL> |
|
13 #include <QWidget> |
|
14 #include <QPainter> |
|
15 #include <QPaintEngine> |
|
16 #include "windowsurfaceimpl_symbian.h" |
|
17 #include "gfxlog.h" |
|
18 |
|
19 namespace Java { namespace GFX { |
|
20 |
|
21 WindowSurfaceImpl::WindowSurfaceImpl(QPaintDevice* aSurface, WindowSurfaceType aType) |
|
22 : mIsBound(false), |
|
23 mBufferedRendering(false), |
|
24 mAutoRefresh(false), |
|
25 mPaintingStarted(false) |
|
26 { |
|
27 GFX_LOG_FUNC_CALL(); |
|
28 mMainSurface.device = aSurface; |
|
29 mMainSurface.type = aType; |
|
30 } |
|
31 |
|
32 WindowSurfaceImpl::WindowSurfaceImpl(QWidget* aWidget, bool aAutoRefresh) |
|
33 : mIsBound(false), |
|
34 mBufferedRendering(false), |
|
35 mAutoRefresh(false), |
|
36 mPaintingStarted(false) |
|
37 { |
|
38 GFX_LOG_FUNC_CALL(); |
|
39 if(aWidget == NULL) |
|
40 { |
|
41 throw GfxException(EGfxErrorIllegalArgument, "Target widget is NULL"); |
|
42 } |
|
43 mMainSurface.widget = aWidget; |
|
44 mAutoRefresh = aAutoRefresh; |
|
45 updateSurfaceData(); |
|
46 } |
|
47 |
|
48 |
|
49 WindowSurfaceImpl::~WindowSurfaceImpl() |
|
50 { |
|
51 GFX_LOG_FUNC_CALL(); |
|
52 if(mMainSurface.localSurface != NULL) |
|
53 { |
|
54 delete mMainSurface.localSurface; |
|
55 mMainSurface.localSurface = NULL; |
|
56 } |
|
57 } |
|
58 |
|
59 void WindowSurfaceImpl::beginPaint(int aX, int aY, int aWidth, int aHeight) |
|
60 { |
|
61 if(mAutoRefresh && (mMainSurface.widget != NULL)) |
|
62 { |
|
63 updateSurfaceData(); |
|
64 } |
|
65 if(!mMainSurface.localSurfaceInUse) |
|
66 { |
|
67 QRegion region(aX, aY, aWidth, aHeight); |
|
68 mMainSurface.qSurface->beginPaint(region); |
|
69 // In case local surface was used last round |
|
70 // and we now have Qt's window surface again |
|
71 // delete the local surface to save memory |
|
72 if(mMainSurface.localSurface != NULL) |
|
73 { |
|
74 delete mMainSurface.localSurface; |
|
75 mMainSurface.localSurface = NULL; |
|
76 } |
|
77 } |
|
78 mPaintingStarted = true; |
|
79 } |
|
80 |
|
81 void WindowSurfaceImpl::endPaint() |
|
82 { |
|
83 if(!mMainSurface.localSurfaceInUse) |
|
84 { |
|
85 mMainSurface.qSurface->endPaint(QRegion()); |
|
86 } |
|
87 mPaintingStarted = false; |
|
88 } |
|
89 |
|
90 void WindowSurfaceImpl::flush() |
|
91 { |
|
92 if(!mMainSurface.localSurfaceInUse) |
|
93 { |
|
94 QRegion region(0,0,mMainSurface.device->width(), mMainSurface.device->height()); |
|
95 mMainSurface.qSurface->flush(mMainSurface.widget, region, QPoint()); |
|
96 } |
|
97 } |
|
98 |
|
99 void WindowSurfaceImpl::bind(int aCapabilies) |
|
100 { |
|
101 GFX_LOG_FUNC_CALL(); |
|
102 // Bind is not allowed if beginPaint has not been called |
|
103 if(!mPaintingStarted) |
|
104 { |
|
105 throw GfxException(EGfxErrorIllegalState, "beginPaint() not called before bind()"); |
|
106 } |
|
107 |
|
108 switch (mMainSurface.type) |
|
109 { |
|
110 case WsTypeQtImage: |
|
111 { |
|
112 mBufferedRendering = true; |
|
113 break; |
|
114 } |
|
115 |
|
116 case WsTypeEglSurface: |
|
117 { |
|
118 // If caller does not support EGL surface |
|
119 // create temp buffer to be used as target and |
|
120 // copy pixels from window surface to temp buffer |
|
121 if ((aCapabilies & WsTypeEglSurface) == 0) { |
|
122 // TODO copy pixels from EGL surface to |
|
123 // QImage created here |
|
124 |
|
125 } else { |
|
126 // Caller supports EGL surface, so just |
|
127 // save EGL state here |
|
128 saveEglState(); |
|
129 } |
|
130 break; |
|
131 } |
|
132 case WsTypeSymbianBitmap: |
|
133 { |
|
134 break; |
|
135 } |
|
136 default: |
|
137 { |
|
138 // we should newer get here |
|
139 } |
|
140 } |
|
141 mIsBound = true; |
|
142 } |
|
143 |
|
144 int WindowSurfaceImpl::getType() |
|
145 { |
|
146 GFX_LOG_FUNC_CALL(); |
|
147 return mMainSurface.type; |
|
148 } |
|
149 |
|
150 QPaintDevice* WindowSurfaceImpl::getDevice() |
|
151 { |
|
152 return mMainSurface.device; |
|
153 } |
|
154 |
|
155 |
|
156 EGLSurface WindowSurfaceImpl::getEglSurface() |
|
157 { |
|
158 return mEgl.drawSurface; |
|
159 } |
|
160 |
|
161 EGLenum WindowSurfaceImpl::getEglApi() |
|
162 { |
|
163 return mEgl.api; |
|
164 } |
|
165 |
|
166 CFbsBitmap* WindowSurfaceImpl::getSymbianBitmap() |
|
167 { |
|
168 return mMainSurface.symbianBitmap; |
|
169 } |
|
170 |
|
171 QImage* WindowSurfaceImpl::getQtImage() |
|
172 { |
|
173 return mMainSurface.localSurface; |
|
174 } |
|
175 |
|
176 void WindowSurfaceImpl::refresh() |
|
177 { |
|
178 updateSurfaceData(); |
|
179 } |
|
180 |
|
181 void WindowSurfaceImpl::release() |
|
182 { |
|
183 GFX_LOG_FUNC_CALL(); |
|
184 if (!mIsBound) |
|
185 { |
|
186 return; |
|
187 } |
|
188 |
|
189 if (mBufferedRendering) |
|
190 { |
|
191 // TODO draw QImage with painter to actual target |
|
192 } |
|
193 else |
|
194 { |
|
195 if(mMainSurface.type == WsTypeEglSurface) |
|
196 { |
|
197 restoreEglState(); |
|
198 } |
|
199 // pixels are already rendered to the target |
|
200 // no post blitter hook needed |
|
201 } |
|
202 mIsBound = false; |
|
203 } |
|
204 |
|
205 void WindowSurfaceImpl::dispose() |
|
206 { |
|
207 GFX_LOG_FUNC_CALL(); |
|
208 delete this; |
|
209 } |
|
210 |
|
211 void WindowSurfaceImpl::saveEglState() |
|
212 { |
|
213 // Some painter needs to be active on the device |
|
214 // in order to get correct data from EGL, so if |
|
215 // there's no active painter, activate one here |
|
216 if(!mMainSurface.device->paintingActive()) |
|
217 { |
|
218 mPainter.begin(mMainSurface.device); |
|
219 } |
|
220 mEgl.drawSurface = eglGetCurrentSurface(EGL_DRAW); |
|
221 mEgl.readSurface = eglGetCurrentSurface(EGL_READ); |
|
222 mEgl.display = eglGetCurrentDisplay(); |
|
223 mEgl.context = eglGetCurrentContext(); |
|
224 mEgl.api = eglQueryAPI(); |
|
225 } |
|
226 |
|
227 void WindowSurfaceImpl::restoreEglState() |
|
228 { |
|
229 eglBindAPI(mEgl.api); |
|
230 eglMakeCurrent(mEgl.display, mEgl.drawSurface, mEgl.readSurface, mEgl.context); |
|
231 |
|
232 // if owned painter was activate to the device |
|
233 // release it |
|
234 if(mPainter.isActive()) |
|
235 { |
|
236 mPainter.end(); |
|
237 } |
|
238 } |
|
239 |
|
240 // Private methods |
|
241 |
|
242 void WindowSurfaceImpl::createLocalSurface(int aWidth, int aHeight) |
|
243 { |
|
244 mMainSurface.localSurface = new QImage(aWidth, aHeight, QImage::Format_ARGB32); |
|
245 if(mMainSurface.localSurface->isNull()) |
|
246 { |
|
247 throw GfxException(EGfxErrorNoMemory, "Local Surface creation failed"); |
|
248 } |
|
249 } |
|
250 |
|
251 void WindowSurfaceImpl::deleteLocalSurface() |
|
252 { |
|
253 if(mMainSurface.localSurface != NULL) |
|
254 { |
|
255 delete mMainSurface.localSurface; |
|
256 mMainSurface.localSurface = NULL; |
|
257 } |
|
258 |
|
259 } |
|
260 |
|
261 bool WindowSurfaceImpl::isLocalSurfaceValid() |
|
262 { |
|
263 if(mMainSurface.localSurface == NULL) |
|
264 { |
|
265 return false; |
|
266 } |
|
267 |
|
268 if((mMainSurface.localSurfaceInUse) && |
|
269 (mMainSurface.localSurface->width() == mMainSurface.widget->width()) && |
|
270 (mMainSurface.localSurface->height() == mMainSurface.widget->height())) |
|
271 { |
|
272 return true; |
|
273 } |
|
274 return false; |
|
275 } |
|
276 |
|
277 void WindowSurfaceImpl::updateSurfaceData() |
|
278 { |
|
279 // If painting is active, i.e. beginPaint has been called |
|
280 // surface data is not updated |
|
281 if(mPaintingStarted) |
|
282 { |
|
283 return; |
|
284 } |
|
285 QWindowSurface* surface = mMainSurface.widget->windowSurface(); |
|
286 |
|
287 // If window surface is null it means that the widget has been |
|
288 // sent to background and widget's window surface has been deleted, |
|
289 // in such case create own QImage as local surface in order to support |
|
290 // rendering in background |
|
291 if(surface == NULL || surface == 0) |
|
292 { |
|
293 // check if we already have local surface with valid size |
|
294 if(!isLocalSurfaceValid()) |
|
295 { |
|
296 // incase we have invalid surface delete the current one |
|
297 // and create new |
|
298 if(mMainSurface.localSurfaceInUse) |
|
299 { |
|
300 deleteLocalSurface(); |
|
301 } |
|
302 createLocalSurface(mMainSurface.widget->width(), mMainSurface.widget->height()); |
|
303 // set info |
|
304 mMainSurface.qSurface = NULL; |
|
305 mMainSurface.device = mMainSurface.localSurface; |
|
306 mMainSurface.type = WsTypeQtImage; |
|
307 mMainSurface.localSurfaceInUse = true; |
|
308 return; |
|
309 } |
|
310 else |
|
311 { |
|
312 // We have valid local surface so just return |
|
313 return; |
|
314 } |
|
315 } |
|
316 else |
|
317 { |
|
318 // We got Qt's window surface, so in case we had local surface in use |
|
319 // delete it as it's not used anymore |
|
320 if(mMainSurface.localSurfaceInUse) |
|
321 { |
|
322 deleteLocalSurface(); |
|
323 } |
|
324 } |
|
325 |
|
326 // We got window surface so extract information |
|
327 QPaintDevice* device = surface->paintDevice(); |
|
328 if(device->paintingActive()) |
|
329 { |
|
330 throw GfxException(EGfxErrorIllegalState, "Internal error: Device active when refreshing data"); |
|
331 } |
|
332 |
|
333 // Attach painter to device in oder to see which type |
|
334 // of device it is working on |
|
335 mPainter.begin(device); |
|
336 QPaintEngine* engine = mPainter.paintEngine(); |
|
337 |
|
338 // determine the surface type based on the engine used |
|
339 // as Qt does not provide exact info of the surface type |
|
340 switch (engine->type()) |
|
341 { |
|
342 case QPaintEngine::OpenVG: |
|
343 // surface is EGL window surface |
|
344 mMainSurface.type = WsTypeEglSurface; |
|
345 break; |
|
346 case QPaintEngine::Raster: |
|
347 mMainSurface.type = WsTypeSymbianBitmap; |
|
348 if(device->devType() == QInternal::Pixmap) |
|
349 { |
|
350 QPixmap* pixmap = static_cast<QPixmap*>(device); |
|
351 mMainSurface.symbianBitmap = pixmap->toSymbianCFbsBitmap(); |
|
352 } |
|
353 else |
|
354 { |
|
355 throw GfxException(EGfxErrorIllegalArgument, "Unsupported device type"); |
|
356 } |
|
357 break; |
|
358 default: |
|
359 throw GfxException(EGfxErrorIllegalArgument, "Unsupported widget window surface type"); |
|
360 break; |
|
361 } |
|
362 |
|
363 // release painter |
|
364 mPainter.end(); |
|
365 mMainSurface.qSurface = surface; |
|
366 mMainSurface.device = device; |
|
367 mMainSurface.localSurfaceInUse = false; |
|
368 } |
|
369 |
|
370 |
|
371 } // namespace GFX |
|
372 } // namespace Java |