painting/qtextureglyphcache.cpp

Source codeSwitch to Preprocessed file
LineSource CodeCoverage
1/****************************************************************************-
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/****************************************************************************
2** -
3** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -
4** Contact: http://www.qt-project.org/legal -
5** -
6** This file is part of the QtGui module of the Qt Toolkit. -
7** -
8** $QT_BEGIN_LICENSE:LGPL$ -
9** Commercial License Usage -
10** Licensees holding valid commercial Qt licenses may use this file in -
11** accordance with the commercial license agreement provided with the -
12** Software or, alternatively, in accordance with the terms contained in -
13** a written agreement between you and Digia. For licensing terms and -
14** conditions see http://qt.digia.com/licensing. For further information -
15** use the contact form at http://qt.digia.com/contact-us. -
16** -
17** GNU Lesser General Public License Usage -
18** Alternatively, this file may be used under the terms of the GNU Lesser -
19** General Public License version 2.1 as published by the Free Software -
20** Foundation and appearing in the file LICENSE.LGPL included in the -
21** packaging of this file. Please review the following information to -
22** ensure the GNU Lesser General Public License version 2.1 requirements -
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -
24** -
25** In addition, as a special exception, Digia gives you certain additional -
26** rights. These rights are described in the Digia Qt LGPL Exception -
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -
28** -
29** GNU General Public License Usage -
30** Alternatively, this file may be used under the terms of the GNU -
31** General Public License version 3.0 as published by the Free Software -
32** Foundation and appearing in the file LICENSE.GPL included in the -
33** packaging of this file. Please review the following information to -
34** ensure the GNU General Public License version 3.0 requirements will be -
35** met: http://www.gnu.org/copyleft/gpl.html. -
36** -
37** -
38** $QT_END_LICENSE$ -
39** -
40****************************************************************************/ -
41 -
42#include <qmath.h> -
43 -
44#include "qtextureglyphcache_p.h" -
45#include "private/qfontengine_p.h" -
46#include "private/qnumeric_p.h" -
47#include "private/qnativeimage_p.h" -
48 -
49QT_BEGIN_NAMESPACE -
50 -
51// #define CACHE_DEBUG -
52 -
53// returns the highest number closest to v, which is a power of 2 -
54// NB! assumes 32 bit ints -
55static inline int qt_next_power_of_two(int v) -
56{ -
57 v--; -
58 v |= v >> 1; -
59 v |= v >> 2; -
60 v |= v >> 4; -
61 v |= v >> 8; -
62 v |= v >> 16; -
63 ++v; -
64 return v; -
65} -
66 -
67int QTextureGlyphCache::calculateSubPixelPositionCount(glyph_t glyph) const -
68{ -
69 // Test 12 different subpixel positions since it factors into 3*4 so it gives -
70 // the coverage we need. -
71 -
72 QList<QImage> images; -
73 for (int i=0; i<12; ++i) { -
74 QImage img = textureMapForGlyph(glyph, QFixed::fromReal(i / 12.0)); -
75 -
76 if (images.isEmpty()) { -
77 QPainterPath path; -
78 QFixedPoint point; -
79 m_current_fontengine->addGlyphsToPath(&glyph, &point, 1, &path, QTextItem::RenderFlags()); -
80 -
81 // Glyph is space, return 0 to indicate that we need to keep trying -
82 if (path.isEmpty()) -
83 break; -
84 -
85 images.append(img); -
86 } else { -
87 bool found = false; -
88 for (int j=0; j<images.size(); ++j) { -
89 if (images.at(j) == img) { -
90 found = true; -
91 break; -
92 } -
93 } -
94 if (!found) -
95 images.append(img); -
96 } -
97 } -
98 -
99 return images.size(); -
100} -
101 -
102bool QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs, -
103 const QFixedPoint *positions) -
104{ -
105#ifdef CACHE_DEBUG -
106 printf("Populating with %d glyphs\n", numGlyphs); -
107 qDebug() << " -> current transformation: " << m_transform; -
108#endif -
109 -
110 m_current_fontengine = fontEngine; -
111 const int margin = m_current_fontengine->glyphMargin(m_type); -
112 const int paddingDoubled = glyphPadding() * 2; -
113 -
114 bool supportsSubPixelPositions = fontEngine->supportsSubPixelPositions(); -
115 if (fontEngine->m_subPixelPositionCount == 0) { -
116 if (!supportsSubPixelPositions) { -
117 fontEngine->m_subPixelPositionCount = 1; -
118 } else { -
119 int i = 0; -
120 while (fontEngine->m_subPixelPositionCount == 0 && i < numGlyphs) -
121 fontEngine->m_subPixelPositionCount = calculateSubPixelPositionCount(glyphs[i++]); -
122 } -
123 } -
124 -
125 QHash<GlyphAndSubPixelPosition, Coord> listItemCoordinates; -
126 int rowHeight = 0; -
127 -
128 QFontEngine::GlyphFormat format; -
129 switch (m_type) { -
130 case Raster_A8: format = QFontEngine::Format_A8; break; -
131 case Raster_RGBMask: format = QFontEngine::Format_A32; break; -
132 default: format = QFontEngine::Format_Mono; break; -
133 } -
134 -
135 // check each glyph for its metrics and get the required rowHeight. -
136 for (int i=0; i < numGlyphs; ++i) { -
137 const glyph_t glyph = glyphs[i]; -
138 -
139 QFixed subPixelPosition; -
140 if (supportsSubPixelPositions) { -
141 QFixed x = positions != 0 ? positions[i].x : QFixed(); -
142 subPixelPosition = fontEngine->subPixelPositionForX(x); -
143 } -
144 -
145 if (coords.contains(GlyphAndSubPixelPosition(glyph, subPixelPosition))) -
146 continue; -
147 if (listItemCoordinates.contains(GlyphAndSubPixelPosition(glyph, subPixelPosition))) -
148 continue; -
149 glyph_metrics_t metrics = fontEngine->alphaMapBoundingBox(glyph, subPixelPosition, m_transform, format); -
150 -
151#ifdef CACHE_DEBUG -
152 printf("(%4x): w=%.2f, h=%.2f, xoff=%.2f, yoff=%.2f, x=%.2f, y=%.2f\n", -
153 glyph, -
154 metrics.width.toReal(), -
155 metrics.height.toReal(), -
156 metrics.xoff.toReal(), -
157 metrics.yoff.toReal(), -
158 metrics.x.toReal(), -
159 metrics.y.toReal()); -
160#endif -
161 GlyphAndSubPixelPosition key(glyph, subPixelPosition); -
162 int glyph_width = metrics.width.ceil().toInt(); -
163 int glyph_height = metrics.height.ceil().toInt(); -
164 if (glyph_height == 0 || glyph_width == 0) { -
165 // Avoid multiple calls to boundingBox() for non-printable characters -
166 Coord c = { 0, 0, 0, 0, 0, 0 }; -
167 coords.insert(key, c); -
168 continue; -
169 } -
170 glyph_width += margin * 2 + 4; -
171 glyph_height += margin * 2 + 4; -
172 // align to 8-bit boundary -
173 if (m_type == QFontEngineGlyphCache::Raster_Mono) -
174 glyph_width = (glyph_width+7)&~7; -
175 -
176 Coord c = { 0, 0, // will be filled in later -
177 glyph_width, -
178 glyph_height, // texture coords -
179 metrics.x.truncate(), -
180 -metrics.y.truncate() }; // baseline for horizontal scripts -
181 -
182 listItemCoordinates.insert(key, c); -
183 rowHeight = qMax(rowHeight, glyph_height); -
184 } -
185 if (listItemCoordinates.isEmpty()) -
186 return true; -
187 -
188 rowHeight += margin * 2 + paddingDoubled; -
189 -
190 if (m_w == 0) { -
191 if (fontEngine->maxCharWidth() <= QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH) -
192 m_w = QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH; -
193 else -
194 m_w = qt_next_power_of_two(fontEngine->maxCharWidth()); -
195 } -
196 -
197 // now actually use the coords and paint the wanted glyps into cache. -
198 QHash<GlyphAndSubPixelPosition, Coord>::iterator iter = listItemCoordinates.begin(); -
199 int requiredWidth = m_w; -
200 while (iter != listItemCoordinates.end()) { -
201 Coord c = iter.value(); -
202 -
203 m_currentRowHeight = qMax(m_currentRowHeight, c.h + margin * 2); -
204 -
205 if (m_cx + c.w > requiredWidth) { -
206 int new_width = requiredWidth*2; -
207 while (new_width < m_cx + c.w) -
208 new_width *= 2; -
209 if (new_width <= maxTextureWidth()) { -
210 requiredWidth = new_width; -
211 } else { -
212 // no room on the current line, start new glyph strip -
213 m_cx = 0; -
214 m_cy += m_currentRowHeight + paddingDoubled; -
215 m_currentRowHeight = c.h + margin * 2; // New row -
216 } -
217 } -
218 -
219 if (maxTextureHeight() > 0 && m_cy + c.h > maxTextureHeight()) { -
220 // We can't make a cache of the required size, so we bail out -
221 return false; -
222 } -
223 -
224 c.x = m_cx; -
225 c.y = m_cy; -
226 -
227 coords.insert(iter.key(), c); -
228 m_pendingGlyphs.insert(iter.key(), c); -
229 -
230 m_cx += c.w + paddingDoubled; -
231 ++iter; -
232 } -
233 return true; -
234 -
235} -
236 -
237void QTextureGlyphCache::fillInPendingGlyphs() -
238{ -
239 if (m_pendingGlyphs.isEmpty()) -
240 return; -
241 -
242 int requiredHeight = m_h; -
243 int requiredWidth = m_w; // Use a minimum size to avoid a lot of initial reallocations -
244 { -
245 QHash<GlyphAndSubPixelPosition, Coord>::iterator iter = m_pendingGlyphs.begin(); -
246 while (iter != m_pendingGlyphs.end()) { -
247 Coord c = iter.value(); -
248 requiredHeight = qMax(requiredHeight, c.y + c.h); -
249 requiredWidth = qMax(requiredWidth, c.x + c.w); -
250 ++iter; -
251 } -
252 } -
253 -
254 if (isNull() || requiredHeight > m_h || requiredWidth > m_w) { -
255 if (isNull()) -
256 createCache(qt_next_power_of_two(requiredWidth), qt_next_power_of_two(requiredHeight)); -
257 else -
258 resizeCache(qt_next_power_of_two(requiredWidth), qt_next_power_of_two(requiredHeight)); -
259 } -
260 -
261 { -
262 QHash<GlyphAndSubPixelPosition, Coord>::iterator iter = m_pendingGlyphs.begin(); -
263 while (iter != m_pendingGlyphs.end()) { -
264 GlyphAndSubPixelPosition key = iter.key(); -
265 fillTexture(iter.value(), key.glyph, key.subPixelPosition); -
266 -
267 ++iter; -
268 } -
269 } -
270 -
271 m_pendingGlyphs.clear(); -
272} -
273 -
274QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g, QFixed subPixelPosition) const -
275{ -
276 if (m_type == QFontEngineGlyphCache::Raster_RGBMask) -
277 return m_current_fontengine->alphaRGBMapForGlyph(g, subPixelPosition, m_transform); -
278 return m_current_fontengine->alphaMapForGlyph(g, subPixelPosition, m_transform); -
279} -
280 -
281/************************************************************************ -
282 * QImageTextureGlyphCache -
283 */ -
284 -
285void QImageTextureGlyphCache::resizeTextureData(int width, int height) -
286{ -
287 m_image = m_image.copy(0, 0, width, height); -
288} -
289 -
290void QImageTextureGlyphCache::createTextureData(int width, int height) -
291{ -
292 switch (m_type) { -
293 case QFontEngineGlyphCache::Raster_Mono: -
294 m_image = QImage(width, height, QImage::Format_Mono);
never executed (the execution status of this line is deduced): m_image = QImage(width, height, QImage::Format_Mono);
-
295 break;
never executed: break;
0
296 case QFontEngineGlyphCache::Raster_A8: { -
297 m_image = QImage(width, height, QImage::Format_Indexed8);
executed (the execution status of this line is deduced): m_image = QImage(width, height, QImage::Format_Indexed8);
-
298 m_image.fill(0);
executed (the execution status of this line is deduced): m_image.fill(0);
-
299 QVector<QRgb> colors(256);
executed (the execution status of this line is deduced): QVector<QRgb> colors(256);
-
300 QRgb *it = colors.data();
executed (the execution status of this line is deduced): QRgb *it = colors.data();
-
301 for (int i=0; i<256; ++i, ++it)
evaluated: i<256
TRUEFALSE
yes
Evaluation Count:256
yes
Evaluation Count:1
1-256
302 *it = 0xff000000 | i | (i<<8) | (i<<16);
executed: *it = 0xff000000 | i | (i<<8) | (i<<16);
Execution Count:256
256
303 m_image.setColorTable(colors);
executed (the execution status of this line is deduced): m_image.setColorTable(colors);
-
304 break; }
executed: break;
Execution Count:1
1
305 case QFontEngineGlyphCache::Raster_RGBMask: -
306 m_image = QImage(width, height, QImage::Format_RGB32);
never executed (the execution status of this line is deduced): m_image = QImage(width, height, QImage::Format_RGB32);
-
307 break;
never executed: break;
0
308 case QFontEngineGlyphCache::Raster_ARGB: -
309 break;
never executed: break;
0
310 } -
311}
executed: }
Execution Count:1
1
312 -
313void QImageTextureGlyphCache::fillTexture(const Coord &c, glyph_t g, QFixed subPixelPosition) -
314{ -
315 QImage mask = textureMapForGlyph(g, subPixelPosition); -
316 -
317#ifdef CACHE_DEBUG -
318 printf("fillTexture of %dx%d at %d,%d in the cache of %dx%d\n", c.w, c.h, c.x, c.y, m_image.width(), m_image.height()); -
319 if (mask.width() > c.w || mask.height() > c.h) { -
320 printf(" ERROR; mask is bigger than reserved space! %dx%d instead of %dx%d\n", mask.width(), mask.height(), c.w,c.h); -
321 return; -
322 } -
323#endif -
324 -
325 if (m_type == QFontEngineGlyphCache::Raster_RGBMask) { -
326 QImage ref(m_image.bits() + (c.x * 4 + c.y * m_image.bytesPerLine()), -
327 qMax(mask.width(), c.w), qMax(mask.height(), c.h), m_image.bytesPerLine(), -
328 m_image.format()); -
329 QPainter p(&ref); -
330 p.setCompositionMode(QPainter::CompositionMode_Source); -
331 p.fillRect(0, 0, c.w, c.h, QColor(0,0,0,0)); // TODO optimize this -
332 p.drawImage(0, 0, mask); -
333 p.end(); -
334 } else if (m_type == QFontEngineGlyphCache::Raster_Mono) { -
335 if (mask.depth() > 1) { -
336 // TODO optimize this -
337 mask = mask.alphaChannel(); -
338 mask.invertPixels(); -
339 mask = mask.convertToFormat(QImage::Format_Mono); -
340 } -
341 -
342 int mw = qMin(mask.width(), c.w); -
343 int mh = qMin(mask.height(), c.h); -
344 uchar *d = m_image.bits(); -
345 int dbpl = m_image.bytesPerLine(); -
346 -
347 for (int y = 0; y < c.h; ++y) { -
348 uchar *dest = d + (c.y + y) *dbpl + c.x/8; -
349 -
350 if (y < mh) { -
351 uchar *src = mask.scanLine(y); -
352 for (int x = 0; x < c.w/8; ++x) { -
353 if (x < (mw+7)/8) -
354 dest[x] = src[x]; -
355 else -
356 dest[x] = 0; -
357 } -
358 } else { -
359 for (int x = 0; x < c.w/8; ++x) -
360 dest[x] = 0; -
361 } -
362 } -
363 } else { // A8 -
364 int mw = qMin(mask.width(), c.w); -
365 int mh = qMin(mask.height(), c.h); -
366 uchar *d = m_image.bits(); -
367 int dbpl = m_image.bytesPerLine(); -
368 -
369 if (mask.depth() == 1) { -
370 for (int y = 0; y < c.h; ++y) { -
371 uchar *dest = d + (c.y + y) *dbpl + c.x; -
372 if (y < mh) { -
373 uchar *src = (uchar *) mask.scanLine(y); -
374 for (int x = 0; x < c.w; ++x) { -
375 if (x < mw) -
376 dest[x] = (src[x >> 3] & (1 << (7 - (x & 7)))) > 0 ? 255 : 0; -
377 } -
378 } -
379 } -
380 } else if (mask.depth() == 8) { -
381 for (int y = 0; y < c.h; ++y) { -
382 uchar *dest = d + (c.y + y) *dbpl + c.x; -
383 if (y < mh) { -
384 uchar *src = (uchar *) mask.scanLine(y); -
385 for (int x = 0; x < c.w; ++x) { -
386 if (x < mw) -
387 dest[x] = src[x]; -
388 } -
389 } -
390 } -
391 } -
392 } -
393 -
394#ifdef CACHE_DEBUG -
395// QPainter p(&m_image); -
396// p.drawLine( -
397 int margin = m_current_fontengine ? m_current_fontengine->glyphMargin(m_type) : 0; -
398 QPoint base(c.x + margin, c.y + margin + c.baseLineY-1); -
399 if (m_image.rect().contains(base)) -
400 m_image.setPixel(base, 255); -
401 m_image.save(QString::fromLatin1("cache-%1.png").arg(qint64(this))); -
402#endif -
403} -
404 -
405QT_END_NAMESPACE -
406 -
Source codeSwitch to Preprocessed file

Generated by Squish Coco Non-Commercial