|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2010 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 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
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 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "qpixmapdata_vg_p.h" |
|
43 #include "qvgfontglyphcache_p.h" |
|
44 #include <private/qt_s60_p.h> |
|
45 |
|
46 #include <fbs.h> |
|
47 #include <bitdev.h> |
|
48 |
|
49 #ifdef QT_SYMBIAN_SUPPORTS_SGIMAGE |
|
50 # include <sgresource/sgimage.h> |
|
51 # ifdef SYMBIAN_FBSERV_GLYPHDATA // defined in fbs.h |
|
52 # define QT_SYMBIAN_HARDWARE_GLYPH_CACHE |
|
53 # include <graphics/fbsglyphdataiterator.h> |
|
54 # include <private/qfontengine_s60_p.h> |
|
55 # endif |
|
56 #endif |
|
57 |
|
58 QT_BEGIN_NAMESPACE |
|
59 |
|
60 typedef VGImage (*_vgCreateEGLImageTargetKHR)(VGeglImageKHR); |
|
61 static _vgCreateEGLImageTargetKHR qt_vgCreateEGLImageTargetKHR = 0; |
|
62 |
|
63 namespace QVG |
|
64 { |
|
65 VGImage vgCreateEGLImageTargetKHR(VGeglImageKHR eglImage); |
|
66 } |
|
67 |
|
68 VGImage QVG::vgCreateEGLImageTargetKHR(VGeglImageKHR eglImage) |
|
69 { |
|
70 if (!qt_vgCreateEGLImageTargetKHR && QEgl::hasExtension("EGL_KHR_image")) |
|
71 qt_vgCreateEGLImageTargetKHR = (_vgCreateEGLImageTargetKHR) eglGetProcAddress("vgCreateEGLImageTargetKHR"); |
|
72 |
|
73 return qt_vgCreateEGLImageTargetKHR ? qt_vgCreateEGLImageTargetKHR(eglImage) : 0; |
|
74 } |
|
75 |
|
76 extern int qt_vg_pixmap_serial; |
|
77 |
|
78 static CFbsBitmap* createBlitCopy(CFbsBitmap* bitmap) |
|
79 { |
|
80 CFbsBitmap *copy = q_check_ptr(new CFbsBitmap); |
|
81 if(!copy) |
|
82 return 0; |
|
83 |
|
84 if (copy->Create(bitmap->SizeInPixels(), bitmap->DisplayMode()) != KErrNone) { |
|
85 delete copy; |
|
86 copy = 0; |
|
87 |
|
88 return 0; |
|
89 } |
|
90 |
|
91 CFbsBitmapDevice* bitmapDevice = 0; |
|
92 CFbsBitGc *bitmapGc = 0; |
|
93 QT_TRAP_THROWING(bitmapDevice = CFbsBitmapDevice::NewL(copy)); |
|
94 QT_TRAP_THROWING(bitmapGc = CFbsBitGc::NewL()); |
|
95 bitmapGc->Activate(bitmapDevice); |
|
96 |
|
97 bitmapGc->BitBlt(TPoint(), bitmap); |
|
98 |
|
99 delete bitmapGc; |
|
100 delete bitmapDevice; |
|
101 |
|
102 return copy; |
|
103 } |
|
104 |
|
105 #ifdef QT_SYMBIAN_SUPPORTS_SGIMAGE |
|
106 static VGImage sgImageToVGImage(QEglContext *context, const RSgImage &sgImage) |
|
107 { |
|
108 // when "0" used as argument then |
|
109 // default display, context are used |
|
110 if (!context) |
|
111 context = qt_vg_create_context(0, QInternal::Pixmap); |
|
112 |
|
113 VGImage vgImage = VG_INVALID_HANDLE; |
|
114 |
|
115 TInt err = 0; |
|
116 |
|
117 RSgDriver driver; |
|
118 err = driver.Open(); |
|
119 if (err != KErrNone) { |
|
120 return vgImage; |
|
121 } |
|
122 |
|
123 if (sgImage.IsNull()) { |
|
124 driver.Close(); |
|
125 return vgImage; |
|
126 } |
|
127 |
|
128 TSgImageInfo sgImageInfo; |
|
129 err = sgImage.GetInfo(sgImageInfo); |
|
130 if (err != KErrNone) { |
|
131 driver.Close(); |
|
132 return vgImage; |
|
133 } |
|
134 |
|
135 const EGLint KEglImageAttribs[] = {EGL_IMAGE_PRESERVED_SYMBIAN, EGL_TRUE, EGL_NONE}; |
|
136 EGLImageKHR eglImage = QEgl::eglCreateImageKHR(QEgl::display(), |
|
137 EGL_NO_CONTEXT, |
|
138 EGL_NATIVE_PIXMAP_KHR, |
|
139 (EGLClientBuffer)&sgImage, |
|
140 (EGLint*)KEglImageAttribs); |
|
141 |
|
142 if (!eglImage || eglGetError() != EGL_SUCCESS) { |
|
143 driver.Close(); |
|
144 return vgImage; |
|
145 } |
|
146 |
|
147 vgImage = QVG::vgCreateEGLImageTargetKHR(eglImage); |
|
148 if (!vgImage || vgGetError() != VG_NO_ERROR) { |
|
149 QEgl::eglDestroyImageKHR(QEgl::display(), eglImage); |
|
150 driver.Close(); |
|
151 return vgImage; |
|
152 } |
|
153 |
|
154 //setSerialNumber(++qt_vg_pixmap_serial); |
|
155 // release stuff |
|
156 QEgl::eglDestroyImageKHR(QEgl::display(), eglImage); |
|
157 driver.Close(); |
|
158 return vgImage; |
|
159 } |
|
160 #endif |
|
161 |
|
162 void QVGPixmapData::cleanup() |
|
163 { |
|
164 is_null = w = h = 0; |
|
165 recreate = false; |
|
166 source = QImage(); |
|
167 } |
|
168 |
|
169 void QVGPixmapData::fromNativeType(void* pixmap, NativeType type) |
|
170 { |
|
171 if (type == QPixmapData::SgImage && pixmap) { |
|
172 #if defined(QT_SYMBIAN_SUPPORTS_SGIMAGE) && !defined(QT_NO_EGL) |
|
173 RSgImage *sgImage = reinterpret_cast<RSgImage*>(pixmap); |
|
174 destroyImages(); |
|
175 prevSize = QSize(); |
|
176 |
|
177 VGImage vgImage = sgImageToVGImage(context, *sgImage); |
|
178 if (vgImage != VG_INVALID_HANDLE) { |
|
179 w = vgGetParameteri(vgImage, VG_IMAGE_WIDTH); |
|
180 h = vgGetParameteri(vgImage, VG_IMAGE_HEIGHT); |
|
181 d = 32; // We always use ARGB_Premultiplied for VG pixmaps. |
|
182 } |
|
183 |
|
184 is_null = (w <= 0 || h <= 0); |
|
185 source = QImage(); // vgGetImageSubData() some day? |
|
186 recreate = false; |
|
187 prevSize = QSize(w, h); |
|
188 //setSerialNumber(++qt_vg_pixmap_serial); |
|
189 #endif |
|
190 } else if (type == QPixmapData::FbsBitmap) { |
|
191 CFbsBitmap *bitmap = reinterpret_cast<CFbsBitmap*>(pixmap); |
|
192 |
|
193 bool deleteSourceBitmap = false; |
|
194 |
|
195 #ifdef Q_SYMBIAN_HAS_EXTENDED_BITMAP_TYPE |
|
196 |
|
197 // Rasterize extended bitmaps |
|
198 |
|
199 TUid extendedBitmapType = bitmap->ExtendedBitmapType(); |
|
200 if (extendedBitmapType != KNullUid) { |
|
201 bitmap = createBlitCopy(bitmap); |
|
202 deleteSourceBitmap = true; |
|
203 } |
|
204 #endif |
|
205 |
|
206 if (bitmap->IsCompressedInRAM()) { |
|
207 bitmap = createBlitCopy(bitmap); |
|
208 deleteSourceBitmap = true; |
|
209 } |
|
210 |
|
211 TDisplayMode displayMode = bitmap->DisplayMode(); |
|
212 QImage::Format format = qt_TDisplayMode2Format(displayMode); |
|
213 |
|
214 TSize size = bitmap->SizeInPixels(); |
|
215 |
|
216 bitmap->BeginDataAccess(); |
|
217 uchar *bytes = (uchar*)bitmap->DataAddress(); |
|
218 QImage img = QImage(bytes, size.iWidth, size.iHeight, format); |
|
219 img = img.copy(); |
|
220 bitmap->EndDataAccess(); |
|
221 |
|
222 if(displayMode == EGray2) { |
|
223 //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid |
|
224 //So invert mono bitmaps so that masks work correctly. |
|
225 img.invertPixels(); |
|
226 } else if(displayMode == EColor16M) { |
|
227 img = img.rgbSwapped(); // EColor16M is BGR |
|
228 } |
|
229 |
|
230 fromImage(img, Qt::AutoColor); |
|
231 |
|
232 if(deleteSourceBitmap) |
|
233 delete bitmap; |
|
234 } |
|
235 } |
|
236 |
|
237 void* QVGPixmapData::toNativeType(NativeType type) |
|
238 { |
|
239 if (type == QPixmapData::SgImage) { |
|
240 #if defined(QT_SYMBIAN_SUPPORTS_SGIMAGE) && !defined(QT_NO_EGL) |
|
241 toVGImage(); |
|
242 |
|
243 if (!isValid() || vgImage == VG_INVALID_HANDLE) |
|
244 return 0; |
|
245 |
|
246 TInt err = 0; |
|
247 |
|
248 RSgDriver driver; |
|
249 err = driver.Open(); |
|
250 if (err != KErrNone) |
|
251 return 0; |
|
252 |
|
253 TSgImageInfo sgInfo; |
|
254 sgInfo.iPixelFormat = EUidPixelFormatARGB_8888_PRE; |
|
255 sgInfo.iSizeInPixels.SetSize(w, h); |
|
256 sgInfo.iUsage = ESgUsageBitOpenVgImage | ESgUsageBitOpenVgSurface; |
|
257 |
|
258 RSgImage *sgImage = q_check_ptr(new RSgImage()); |
|
259 err = sgImage->Create(sgInfo, NULL, NULL); |
|
260 if (err != KErrNone) { |
|
261 driver.Close(); |
|
262 return 0; |
|
263 } |
|
264 |
|
265 const EGLint KEglImageAttribs[] = {EGL_IMAGE_PRESERVED_SYMBIAN, EGL_TRUE, EGL_NONE}; |
|
266 EGLImageKHR eglImage = QEgl::eglCreateImageKHR(QEgl::display(), |
|
267 EGL_NO_CONTEXT, |
|
268 EGL_NATIVE_PIXMAP_KHR, |
|
269 (EGLClientBuffer)sgImage, |
|
270 (EGLint*)KEglImageAttribs); |
|
271 if (!eglImage || eglGetError() != EGL_SUCCESS) { |
|
272 sgImage->Close(); |
|
273 driver.Close(); |
|
274 return 0; |
|
275 } |
|
276 |
|
277 VGImage dstVgImage = QVG::vgCreateEGLImageTargetKHR(eglImage); |
|
278 if (!dstVgImage || vgGetError() != VG_NO_ERROR) { |
|
279 QEgl::eglDestroyImageKHR(QEgl::display(), eglImage); |
|
280 sgImage->Close(); |
|
281 driver.Close(); |
|
282 return 0; |
|
283 } |
|
284 |
|
285 vgCopyImage(dstVgImage, 0, 0, |
|
286 vgImage, 0, 0, |
|
287 w, h, VG_FALSE); |
|
288 |
|
289 if (vgGetError() != VG_NO_ERROR) { |
|
290 sgImage->Close(); |
|
291 sgImage = 0; |
|
292 } |
|
293 // release stuff |
|
294 vgDestroyImage(dstVgImage); |
|
295 QEgl::eglDestroyImageKHR(QEgl::display(), eglImage); |
|
296 driver.Close(); |
|
297 return reinterpret_cast<void*>(sgImage); |
|
298 #endif |
|
299 } else if (type == QPixmapData::FbsBitmap) { |
|
300 CFbsBitmap *bitmap = q_check_ptr(new CFbsBitmap); |
|
301 |
|
302 if (bitmap) { |
|
303 if (bitmap->Create(TSize(source.width(), source.height()), |
|
304 EColor16MAP) == KErrNone) { |
|
305 const uchar *sptr = const_cast<const QImage&>(source).bits(); |
|
306 bitmap->BeginDataAccess(); |
|
307 |
|
308 uchar *dptr = (uchar*)bitmap->DataAddress(); |
|
309 Mem::Copy(dptr, sptr, source.byteCount()); |
|
310 |
|
311 bitmap->EndDataAccess(); |
|
312 } else { |
|
313 delete bitmap; |
|
314 bitmap = 0; |
|
315 } |
|
316 } |
|
317 |
|
318 return reinterpret_cast<void*>(bitmap); |
|
319 } |
|
320 return 0; |
|
321 } |
|
322 |
|
323 QSymbianVGFontGlyphCache::QSymbianVGFontGlyphCache() : QVGFontGlyphCache() |
|
324 { |
|
325 #ifdef QT_SYMBIAN_HARDWARE_GLYPH_CACHE |
|
326 invertedGlyphs = true; |
|
327 #endif |
|
328 } |
|
329 |
|
330 void QSymbianVGFontGlyphCache::cacheGlyphs(QVGPaintEnginePrivate *d, |
|
331 QFontEngine *fontEngine, |
|
332 const glyph_t *g, int count) |
|
333 { |
|
334 #ifdef QT_SYMBIAN_HARDWARE_GLYPH_CACHE |
|
335 QFontEngineS60 *s60fontEngine = static_cast<QFontEngineS60*>(fontEngine); |
|
336 if (s60fontEngine->m_activeFont->TypeUid() != KCFbsFontUid) |
|
337 return QVGFontGlyphCache::cacheGlyphs(d, fontEngine, g, count); |
|
338 |
|
339 QVector<glyph_t> uncachedGlyphs; |
|
340 while (count-- > 0) { |
|
341 // Skip this glyph if we have already cached it before. |
|
342 glyph_t glyph = *g++; |
|
343 if (((glyph < 256) && ((cachedGlyphsMask[glyph / 32] & (1 << (glyph % 32))) != 0)) |
|
344 || cachedGlyphs.contains(glyph)) |
|
345 continue; |
|
346 if (!uncachedGlyphs.contains(glyph)) |
|
347 uncachedGlyphs.append(glyph); |
|
348 } |
|
349 |
|
350 if (!uncachedGlyphs.isEmpty()) { |
|
351 CFbsFont *cfbsFont = static_cast<CFbsFont *>(s60fontEngine->m_activeFont); |
|
352 RFbsGlyphDataIterator iter; |
|
353 |
|
354 int err = iter.Open(*cfbsFont, (const unsigned int*)uncachedGlyphs.constData(), uncachedGlyphs.count()); |
|
355 |
|
356 if (err == KErrNotSupported || err == KErrInUse) { // Fallback in possibly supported error cases |
|
357 iter.Close(); |
|
358 qWarning("Falling back to default QVGFontGlyphCache"); |
|
359 return QVGFontGlyphCache::cacheGlyphs(d, fontEngine, g, count); |
|
360 } |
|
361 |
|
362 for (; err == KErrNone; err = iter.Next()) { |
|
363 const unsigned int glyph = iter.GlyphCode(); |
|
364 |
|
365 const RSgImage& image = iter.Image(); |
|
366 const TOpenFontCharMetrics& metrics = iter.Metrics(); |
|
367 |
|
368 TRect glyphBounds; |
|
369 metrics.GetHorizBounds(glyphBounds); |
|
370 VGImage vgImage = sgImageToVGImage(0, image); |
|
371 VGfloat origin[2]; |
|
372 VGfloat escapement[2]; |
|
373 origin[0] = -glyphBounds.iTl.iX; |
|
374 origin[1] = glyphBounds.iBr.iY; |
|
375 escapement[0] = 0; |
|
376 escapement[1] = 0; |
|
377 vgSetGlyphToImage(font, glyph, vgImage, origin, escapement); |
|
378 vgDestroyImage(vgImage); |
|
379 |
|
380 // Add to cache |
|
381 if (glyph < 256) |
|
382 cachedGlyphsMask[glyph / 32] |= (1 << (glyph % 32)); |
|
383 else |
|
384 cachedGlyphs.insert(glyph); |
|
385 } |
|
386 iter.Close(); |
|
387 |
|
388 if (err == KErrNoMemory || err == KErrNoGraphicsMemory) |
|
389 qWarning("Not enough memory to cache glyph"); |
|
390 else if (err != KErrNotFound) |
|
391 qWarning("Received error %d from glyph cache", err); |
|
392 } |
|
393 #else |
|
394 QVGFontGlyphCache::cacheGlyphs(d, fontEngine, g, count); |
|
395 #endif |
|
396 } |
|
397 |
|
398 QT_END_NAMESPACE |