Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qtextureglyphcache.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <qmath.h>
5
7#include "private/qfontengine_p.h"
8#include "private/qnumeric_p.h"
9
10#include <QtGui/qpainterpath.h>
11
13
14// #define CACHE_DEBUG
15
16// out-of-line to avoid vtable duplication, breaking e.g. RTTI
20
22{
23 // Test 12 different subpixel positions since it factors into 3*4 so it gives
24 // the coverage we need.
25
26 const int NumSubpixelPositions = 12;
27
28 QImage images[NumSubpixelPositions];
29 int numImages = 0;
30 for (int i = 0; i < NumSubpixelPositions; ++i) {
32
33 if (numImages == 0) {
35 QFixedPoint point;
36 m_current_fontengine->addGlyphsToPath(&glyph, &point, 1, &path, QTextItem::RenderFlags());
37
38 // Glyph is space, return 0 to indicate that we need to keep trying
39 if (path.isEmpty())
40 break;
41
42 images[numImages++] = std::move(img);
43 } else {
44 bool found = false;
45 for (int j = 0; j < numImages; ++j) {
46 if (images[j] == img) {
47 found = true;
48 break;
49 }
50 }
51 if (!found)
52 images[numImages++] = std::move(img);
53 }
54 }
55
56 return numImages;
57}
58
61 const glyph_t *glyphs,
63 QPainter::RenderHints renderHints,
64 bool includeGlyphCacheScale)
65{
66#ifdef CACHE_DEBUG
67 printf("Populating with %lld glyphs\n", static_cast<long long>(numGlyphs));
68 qDebug() << " -> current transformation: " << m_transform;
69#endif
70
71 m_current_fontengine = fontEngine;
72 const int padding = glyphPadding();
73 const int paddingDoubled = padding * 2;
74
75 bool supportsSubPixelPositions = fontEngine->supportsSubPixelPositions();
76 bool verticalSubPixelPositions = fontEngine->supportsVerticalSubPixelPositions()
77 && (renderHints & QPainter::VerticalSubpixelPositioning) != 0;
78 if (fontEngine->m_subPixelPositionCount == 0) {
79 if (!supportsSubPixelPositions) {
80 fontEngine->m_subPixelPositionCount = 1;
81 } else {
82 qsizetype i = 0;
83 while (fontEngine->m_subPixelPositionCount == 0 && i < numGlyphs)
85 }
86 }
87
88 if (m_cx == 0 && m_cy == 0) {
89 m_cx = padding;
90 m_cy = padding;
91 }
92
93 qreal glyphCacheScaleX = transform().m11();
94 qreal glyphCacheScaleY = transform().m22();
95
96 QHash<GlyphAndSubPixelPosition, Coord> listItemCoordinates;
97 int rowHeight = 0;
98
99 // check each glyph for its metrics and get the required rowHeight.
100 for (qsizetype i = 0; i < numGlyphs; ++i) {
101 const glyph_t glyph = glyphs[i];
102
103 QFixedPoint subPixelPosition;
104 if (supportsSubPixelPositions) {
105 QFixedPoint pos = positions != nullptr ? positions[i] : QFixedPoint();
106 if (includeGlyphCacheScale) {
107 pos = QFixedPoint(QFixed::fromReal(pos.x.toReal() * glyphCacheScaleX),
108 QFixed::fromReal(pos.y.toReal() * glyphCacheScaleY));
109 }
110 subPixelPosition = fontEngine->subPixelPositionFor(pos);
111 if (!verticalSubPixelPositions)
112 subPixelPosition.y = 0;
113 }
114
115 if (coords.contains(GlyphAndSubPixelPosition(glyph, subPixelPosition)))
116 continue;
117 if (listItemCoordinates.contains(GlyphAndSubPixelPosition(glyph, subPixelPosition)))
118 continue;
119
120 glyph_metrics_t metrics = fontEngine->alphaMapBoundingBox(glyph, subPixelPosition, m_transform, m_format);
121
122#ifdef CACHE_DEBUG
123 printf("(%4x): w=%.2f, h=%.2f, xoff=%.2f, yoff=%.2f, x=%.2f, y=%.2f\n",
124 glyph,
125 metrics.width.toReal(),
126 metrics.height.toReal(),
127 metrics.xoff.toReal(),
128 metrics.yoff.toReal(),
129 metrics.x.toReal(),
130 metrics.y.toReal());
131#endif
132 GlyphAndSubPixelPosition key(glyph, subPixelPosition);
133 int glyph_width = metrics.width.ceil().toInt();
134 int glyph_height = metrics.height.ceil().toInt();
135 if (glyph_height == 0 || glyph_width == 0) {
136 // Avoid multiple calls to boundingBox() for non-printable characters
137 Coord c = { 0, 0, 0, 0, 0, 0 };
138 coords.insert(key, c);
139 continue;
140 }
141 // align to 8-bit boundary
143 glyph_width = (glyph_width+7)&~7;
144
145 Coord c = { 0, 0, // will be filled in later
146 glyph_width,
147 glyph_height, // texture coords
148 metrics.x.truncate(),
149 -metrics.y.truncate() }; // baseline for horizontal scripts
150
151 listItemCoordinates.insert(key, c);
152 rowHeight = qMax(rowHeight, glyph_height);
153 }
154 if (listItemCoordinates.isEmpty())
155 return true;
156
157 rowHeight += paddingDoubled;
158
159 if (m_w == 0) {
162 else
163 m_w = qNextPowerOfTwo(qCeil(fontEngine->maxCharWidth()) - 1);
164 }
165
166 // now actually use the coords and paint the wanted glyps into cache.
167 QHash<GlyphAndSubPixelPosition, Coord>::iterator iter = listItemCoordinates.begin();
168 int requiredWidth = m_w;
169 while (iter != listItemCoordinates.end()) {
170 Coord c = iter.value();
171
173
174 if (m_cx + c.w + padding > requiredWidth) {
175 int new_width = requiredWidth*2;
176 while (new_width < m_cx + c.w + padding)
177 new_width *= 2;
178 if (new_width <= maxTextureWidth()) {
179 requiredWidth = new_width;
180 } else {
181 // no room on the current line, start new glyph strip
182 m_cx = padding;
183 m_cy += m_currentRowHeight + paddingDoubled;
184 m_currentRowHeight = c.h; // New row
185 }
186 }
187
188 if (maxTextureHeight() > 0 && m_cy + c.h + padding > maxTextureHeight()) {
189 // We can't make a cache of the required size, so we bail out
190 return false;
191 }
192
193 c.x = m_cx;
194 c.y = m_cy;
195
196 coords.insert(iter.key(), c);
197 m_pendingGlyphs.insert(iter.key(), c);
198
199 m_cx += c.w + paddingDoubled;
200 ++iter;
201 }
202 return true;
203
204}
205
207{
208 if (!hasPendingGlyphs())
209 return;
210
211 int requiredHeight = m_h;
212 int requiredWidth = m_w; // Use a minimum size to avoid a lot of initial reallocations
213 {
215 while (iter != m_pendingGlyphs.end()) {
216 Coord c = iter.value();
217 requiredHeight = qMax(requiredHeight, c.y + c.h);
218 requiredWidth = qMax(requiredWidth, c.x + c.w);
219 ++iter;
220 }
221 }
222
223 if (isNull() || requiredHeight > m_h || requiredWidth > m_w) {
224 if (isNull())
225 createCache(qNextPowerOfTwo(requiredWidth - 1), qNextPowerOfTwo(requiredHeight - 1));
226 else
227 resizeCache(qNextPowerOfTwo(requiredWidth - 1), qNextPowerOfTwo(requiredHeight - 1));
228 }
229
231 {
233 while (iter != m_pendingGlyphs.end()) {
235 fillTexture(iter.value(), key.glyph, key.subPixelPosition);
236
237 ++iter;
238 }
239 }
241
242 m_pendingGlyphs.clear();
243}
244
246{
247 switch (m_format) {
249 return m_current_fontengine->alphaRGBMapForGlyph(g, subPixelPosition, m_transform);
251 return m_current_fontengine->bitmapForGlyph(g, subPixelPosition, m_transform, color());
252 default:
253 return m_current_fontengine->alphaMapForGlyph(g, subPixelPosition, m_transform);
254 }
255}
256
257/************************************************************************
258 * QImageTextureGlyphCache
259 */
260
261// out-of-line to avoid vtable duplication, breaking e.g. RTTI
265
267{
268 m_image = m_image.copy(0, 0, width, height);
269 // Regions not part of the copy are initialized to 0, and that is just what
270 // we need.
271}
272
274{
275 switch (m_format) {
278 break;
281 break;
284 break;
287 break;
288 default:
289 Q_UNREACHABLE();
290 }
291
292 // Regions not touched by the glyphs must be initialized to 0. (such
293 // locations may in fact be sampled with styled (shifted) text materials)
294 // When resizing, the QImage copy() does this implicitly but the initial
295 // contents must be zeroed out explicitly here.
296 m_image.fill(0);
297}
298
300 glyph_t g,
301 const QFixedPoint &subPixelPosition)
302{
303 QImage mask = textureMapForGlyph(g, subPixelPosition);
304
305#ifdef CACHE_DEBUG
306 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());
307 if (mask.width() > c.w || mask.height() > c.h) {
308 printf(" ERROR; mask is bigger than reserved space! %dx%d instead of %dx%d\n", mask.width(), mask.height(), c.w,c.h);
309 return;
310 }
311#endif
312 Q_ASSERT(mask.width() <= c.w && mask.height() <= c.h);
313
316 QImage ref(m_image.bits() + (c.x * 4 + c.y * m_image.bytesPerLine()),
317 qMin(mask.width(), c.w), qMin(mask.height(), c.h), m_image.bytesPerLine(),
318 m_image.format());
319 QPainter p(&ref);
320 p.setCompositionMode(QPainter::CompositionMode_Source);
321 p.fillRect(0, 0, c.w, c.h, QColor(0,0,0,0)); // TODO optimize this
322 p.drawImage(0, 0, mask);
323 p.end();
324 } else if (m_format == QFontEngine::Format_Mono) {
325 if (mask.depth() > 1) {
326 // TODO optimize this
327 mask.convertTo(QImage::Format_Alpha8);
328 mask.reinterpretAsFormat(QImage::Format_Grayscale8);
329 mask.invertPixels();
331 }
332
333 int mw = qMin(mask.width(), c.w);
334 int mh = qMin(mask.height(), c.h);
335 uchar *d = m_image.bits();
336 qsizetype dbpl = m_image.bytesPerLine();
337
338 for (int y = 0; y < c.h; ++y) {
339 uchar *dest = d + (c.y + y) *dbpl + c.x/8;
340
341 if (y < mh) {
342 const uchar *src = mask.constScanLine(y);
343 for (int x = 0; x < c.w/8; ++x) {
344 if (x < (mw+7)/8)
345 dest[x] = src[x];
346 else
347 dest[x] = 0;
348 }
349 } else {
350 for (int x = 0; x < c.w/8; ++x)
351 dest[x] = 0;
352 }
353 }
354 } else { // A8
355 int mw = qMin(mask.width(), c.w);
356 int mh = qMin(mask.height(), c.h);
357 uchar *d = m_image.bits();
358 qsizetype dbpl = m_image.bytesPerLine();
359
360 if (mask.depth() == 1) {
361 for (int y = 0; y < c.h; ++y) {
362 uchar *dest = d + (c.y + y) *dbpl + c.x;
363 if (y < mh) {
364 const uchar *src = mask.constScanLine(y);
365 for (int x = 0; x < c.w; ++x) {
366 if (x < mw)
367 dest[x] = (src[x >> 3] & (1 << (7 - (x & 7)))) > 0 ? 255 : 0;
368 }
369 }
370 }
371 } else if (mask.depth() == 8) {
372 for (int y = 0; y < c.h; ++y) {
373 uchar *dest = d + (c.y + y) *dbpl + c.x;
374 if (y < mh) {
375 const uchar *src = mask.constScanLine(y);
376 for (int x = 0; x < c.w; ++x) {
377 if (x < mw)
378 dest[x] = src[x];
379 }
380 }
381 }
382 }
383 }
384
385#ifdef CACHE_DEBUG
386// QPainter p(&m_image);
387// p.drawLine(
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
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
const QTransform & transform() const
QFontEngine::GlyphFormat m_format
const QColor & color() const
virtual QImage bitmapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t, const QColor &color=QColor())
virtual glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, const QFixedPoint &, const QTransform &matrix, GlyphFormat)
int m_subPixelPositionCount
virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, QPainterPath *path, QTextItem::RenderFlags flags)
virtual qreal maxCharWidth() const =0
virtual int glyphMargin(GlyphFormat format)
virtual QImage alphaMapForGlyph(glyph_t)
virtual QImage alphaRGBMapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t)
virtual bool supportsVerticalSubPixelPositions() const
bool supportsSubPixelPositions() const
virtual QFixedPoint subPixelPositionFor(const QFixedPoint &position) const
\inmodule QtCore
Definition qhash.h:1103
virtual void createTextureData(int width, int height) override
virtual void resizeTextureData(int width, int height) override
virtual void fillTexture(const Coord &c, glyph_t glyph, const QFixedPoint &subPixelPosition) override
\inmodule QtGui
Definition qimage.h:37
qsizetype bytesPerLine() const
Returns the number of bytes per image scanline.
Definition qimage.cpp:1560
void setPixel(int x, int y, uint index_or_rgb)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qimage.cpp:2588
QImage copy(const QRect &rect=QRect()) const
Returns a sub-area of the image as a new image.
int width() const
Returns the width of the image.
bool save(const QString &fileName, const char *format=nullptr, int quality=-1) const
Saves the image to the file with the given fileName, using the given image file format and quality fa...
Definition qimage.cpp:3888
uchar * bits()
Returns a pointer to the first pixel data.
Definition qimage.cpp:1698
int height() const
Returns the height of the image.
@ Format_Alpha8
Definition qimage.h:65
@ Format_RGB32
Definition qimage.h:46
@ Format_Mono
Definition qimage.h:43
@ Format_ARGB32_Premultiplied
Definition qimage.h:48
@ Format_Grayscale8
Definition qimage.h:66
void fill(uint pixel)
Fills the entire image with the given pixelValue.
Definition qimage.cpp:1758
Format format() const
Returns the format of the image.
Definition qimage.cpp:2162
QRect rect() const
Returns the enclosing rectangle (0, 0, width(), height()) of the image.
\inmodule QtGui
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
@ VerticalSubpixelPositioning
Definition qpainter.h:55
@ CompositionMode_Source
Definition qpainter.h:101
\inmodule QtCore\reentrant
Definition qpoint.h:25
bool contains(const QRect &r, bool proper=false) const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qrect.cpp:855
QAtomicInt ref
Definition qshareddata.h:21
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
QFontEngine * m_current_fontengine
int calculateSubPixelPositionCount(glyph_t) const
virtual int maxTextureHeight() const
void resizeCache(int width, int height)
virtual void endFillTexture()
virtual void fillTexture(const Coord &coord, glyph_t glyph, const QFixedPoint &subPixelPosition)=0
virtual void beginFillTexture()
QImage textureMapForGlyph(glyph_t g, const QFixedPoint &subPixelPosition) const
void createCache(int width, int height)
QHash< GlyphAndSubPixelPosition, Coord > m_pendingGlyphs
bool populate(QFontEngine *fontEngine, qsizetype numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions, QPainter::RenderHints renderHints=QPainter::RenderHints(), bool includeGlyphCacheScale=false)
virtual int maxTextureWidth() const
virtual int glyphPadding() const
qreal m11() const
Returns the horizontal scaling factor.
Definition qtransform.h:199
qreal m22() const
Returns the vertical scaling factor.
Definition qtransform.h:215
Combined button and popup list for selecting options.
@ ThresholdDither
Definition qnamespace.h:492
static const QCssKnownValue positions[NumKnownPositionModes - 1]
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter * iter
#define qDebug
[1]
Definition qlogging.h:164
constexpr quint32 qNextPowerOfTwo(quint32 v)
Definition qmath.h:335
int qCeil(T v)
Definition qmath.h:36
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLint GLint GLint GLint GLint x
[0]
GLuint64 key
GLint GLsizei GLsizei height
GLsizei const GLubyte GLsizei GLenum const void * coords
GLenum const void GLbitfield GLsizei numGlyphs
GLsizei GLenum const void GLuint GLsizei GLfloat * metrics
GLenum src
GLint GLsizei width
GLboolean GLboolean g
GLint ref
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLint y
const GLubyte * c
GLint void * img
Definition qopenglext.h:233
GLsizei const GLchar *const * path
GLfloat GLfloat p
[1]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int void * arg
unsigned int glyph_t
#define QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH
unsigned char uchar
Definition qtypes.h:32
ptrdiff_t qsizetype
Definition qtypes.h:165
long long qint64
Definition qtypes.h:60
double qreal
Definition qtypes.h:187
static const uint base
Definition qurlidna.cpp:20
QList< QImage > images
[6]
QFixed y
Definition qfixed_p.h:163
static constexpr QFixed fromReal(qreal r)
Definition qfixed_p.h:35