qtextureglyphcache.cpp

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

Generated by Squish Coco Non-Commercial 4.3.0-BETA-master-30-08-2018-4cb69e9