22int QTextureGlyphCache::calculateSubPixelPositionCount(glyph_t glyph)
const
27 const int NumSubpixelPositions = 12;
29 QImage images[NumSubpixelPositions];
31 for (
int i = 0; i < NumSubpixelPositions; ++i) {
32 QImage img = textureMapForGlyph(glyph, QFixedPoint(QFixed::fromReal(i / 12.0), 0));
37 m_current_fontengine->addGlyphsToPath(&glyph, &point, 1, &path, QTextItem::RenderFlags());
43 images[numImages++] = std::move(img);
46 for (
int j = 0; j < numImages; ++j) {
47 if (images[j] == img) {
53 images[numImages++] = std::move(img);
60bool QTextureGlyphCache::populate(QFontEngine *fontEngine,
62 const glyph_t *glyphs,
63 const QFixedPoint *positions,
64 QPainter::RenderHints renderHints,
65 bool includeGlyphCacheScale)
68 printf(
"Populating with %lld glyphs\n",
static_cast<
long long>(numGlyphs));
69 qDebug() <<
" -> current transformation: " << m_transform;
72 m_current_fontengine = fontEngine;
73 const int padding = glyphPadding();
74 const int paddingDoubled = padding * 2;
76 bool supportsSubPixelPositions = fontEngine->supportsSubPixelPositions();
77 bool verticalSubPixelPositions = fontEngine->supportsVerticalSubPixelPositions()
78 && (renderHints & QPainter::VerticalSubpixelPositioning) != 0;
79 if (fontEngine->m_subPixelPositionCount == 0) {
80 if (!supportsSubPixelPositions) {
81 fontEngine->m_subPixelPositionCount = 1;
84 while (fontEngine->m_subPixelPositionCount == 0 && i < numGlyphs)
85 fontEngine->m_subPixelPositionCount = calculateSubPixelPositionCount(glyphs[i++]);
89 if (m_cx == 0 && m_cy == 0) {
94 qreal glyphCacheScaleX = transform().m11();
95 qreal glyphCacheScaleY = transform().m22();
97 QHash<GlyphAndSubPixelPosition, Coord> listItemCoordinates;
101 for (qsizetype i = 0; i < numGlyphs; ++i) {
102 const glyph_t glyph = glyphs[i];
104 QFixedPoint subPixelPosition;
105 if (supportsSubPixelPositions) {
106 QFixedPoint pos = positions !=
nullptr ? positions[i] : QFixedPoint();
107 if (includeGlyphCacheScale) {
108 pos = QFixedPoint(QFixed::fromReal(pos.x.toReal() * glyphCacheScaleX),
109 QFixed::fromReal(pos.y.toReal() * glyphCacheScaleY));
111 subPixelPosition = fontEngine->subPixelPositionFor(pos);
112 if (!verticalSubPixelPositions)
113 subPixelPosition.y = 0;
116 if (coords.contains(GlyphAndSubPixelPosition(glyph, subPixelPosition)))
118 if (listItemCoordinates.contains(GlyphAndSubPixelPosition(glyph, subPixelPosition)))
121 glyph_metrics_t metrics = fontEngine->alphaMapBoundingBox(glyph, subPixelPosition, m_transform, m_format);
124 printf(
"(%4x): w=%.2f, h=%.2f, xoff=%.2f, yoff=%.2f, x=%.2f, y=%.2f\n",
126 metrics.width.toReal(),
127 metrics.height.toReal(),
128 metrics.xoff.toReal(),
129 metrics.yoff.toReal(),
133 GlyphAndSubPixelPosition key(glyph, subPixelPosition);
134 int glyph_width = metrics.width.ceil().toInt();
135 int glyph_height = metrics.height.ceil().toInt();
136 if (glyph_height == 0 || glyph_width == 0) {
138 Coord c = { 0, 0, 0, 0, 0, 0 };
139 coords.insert(key, c);
143 if (m_format == QFontEngine::Format_Mono)
144 glyph_width = (glyph_width+7)&~7;
149 metrics.x.truncate(),
150 -metrics.y.truncate() };
152 listItemCoordinates.insert(key, c);
153 rowHeight = qMax(rowHeight, glyph_height);
155 if (listItemCoordinates.isEmpty())
158 rowHeight += paddingDoubled;
164 m_w = qNextPowerOfTwo(qCeil(fontEngine->maxCharWidth()) - 1);
168 QHash<GlyphAndSubPixelPosition, Coord>::iterator iter = listItemCoordinates.begin();
169 int requiredWidth = m_w;
170 while (iter != listItemCoordinates.end()) {
171 Coord c = iter.value();
173 m_currentRowHeight = qMax(m_currentRowHeight, c.h);
175 if (m_cx + c.w + padding > requiredWidth) {
176 int new_width = requiredWidth*2;
177 while (new_width < m_cx + c.w + padding)
179 if (new_width <= maxTextureWidth()) {
180 requiredWidth = new_width;
184 m_cy += m_currentRowHeight + paddingDoubled;
185 m_currentRowHeight = c.h;
189 if (maxTextureHeight() > 0 && m_cy + c.h + padding > maxTextureHeight()) {
197 coords.insert(iter.key(), c);
198 m_pendingGlyphs.insert(iter.key(), c);
200 m_cx += c.w + paddingDoubled;
207void QTextureGlyphCache::fillInPendingGlyphs()
209 if (!hasPendingGlyphs())
212 int requiredHeight = m_h;
213 int requiredWidth = m_w;
214 const int padding = glyphPadding();
216 QHash<GlyphAndSubPixelPosition, Coord>::iterator iter = m_pendingGlyphs.begin();
217 while (iter != m_pendingGlyphs.end()) {
218 Coord c = iter.value();
219 requiredHeight = qMax(requiredHeight, c.y + c.h + padding);
220 requiredWidth = qMax(requiredWidth, c.x + c.w + padding);
225 if (isNull() || requiredHeight > m_h || requiredWidth > m_w) {
227 createCache(qNextPowerOfTwo(requiredWidth - 1), qNextPowerOfTwo(requiredHeight - 1));
229 resizeCache(qNextPowerOfTwo(requiredWidth - 1), qNextPowerOfTwo(requiredHeight - 1));
234 QHash<GlyphAndSubPixelPosition, Coord>::iterator iter = m_pendingGlyphs.begin();
235 while (iter != m_pendingGlyphs.end()) {
236 GlyphAndSubPixelPosition key = iter.key();
237 fillTexture(iter.value(), key.glyph, key.subPixelPosition);
244 m_pendingGlyphs.clear();
275void QImageTextureGlyphCache::createTextureData(
int width,
int height)
278 case QFontEngine::Format_Mono:
279 m_image = QImage(width, height, QImage::Format_Mono);
281 case QFontEngine::Format_A8:
282 m_image = QImage(width, height, QImage::Format_Alpha8);
284 case QFontEngine::Format_A32:
285 m_image = QImage(width, height, QImage::Format_RGB32);
287 case QFontEngine::Format_ARGB:
288 m_image = QImage(width, height, QImage::Format_ARGB32_Premultiplied);
301void QImageTextureGlyphCache::fillTexture(
const Coord &c,
303 const QFixedPoint &subPixelPosition)
305 QImage mask = textureMapForGlyph(g, subPixelPosition);
310 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());
311 if (mask.width() > c.w || mask.height() > c.h) {
312 printf(
" ERROR; mask is bigger than reserved space! %dx%d instead of %dx%d\n", mask.width(), mask.height(), c.w,c.h);
316 if (m_format == QFontEngine::Format_A32
317 || m_format == QFontEngine::Format_ARGB) {
318 QImage ref(m_image.bits() + (c.x * 4 + c.y * m_image.bytesPerLine()),
319 qMin(mask.width(), c.w), qMin(mask.height(), c.h), m_image.bytesPerLine(),
322 p.setCompositionMode(QPainter::CompositionMode_Source);
323 p.fillRect(0, 0, c.w, c.h, QColor(0,0,0,0));
324 p.drawImage(0, 0, mask);
326 }
else if (m_format == QFontEngine::Format_Mono) {
327 if (mask.depth() > 1) {
329 mask.convertTo(QImage::Format_Alpha8);
330 mask.reinterpretAsFormat(QImage::Format_Grayscale8);
332 mask.convertTo(QImage::Format_Mono, Qt::ThresholdDither);
335 int mw = qMin(mask.width(), c.w);
336 int mh = qMin(mask.height(), c.h);
337 uchar *d = m_image.bits();
338 qsizetype dbpl = m_image.bytesPerLine();
340 for (
int y = 0; y < c.h; ++y) {
341 uchar *dest = d + (c.y + y) *dbpl + c.x/8;
344 const uchar *src = mask.constScanLine(y);
345 for (
int x = 0; x < c.w/8; ++x) {
352 for (
int x = 0; x < c.w/8; ++x)
357 int mw = qMin(mask.width(), c.w);
358 int mh = qMin(mask.height(), c.h);
359 uchar *d = m_image.bits();
360 qsizetype dbpl = m_image.bytesPerLine();
362 if (mask.depth() == 1) {
363 for (
int y = 0; y < c.h; ++y) {
364 uchar *dest = d + (c.y + y) *dbpl + c.x;
366 const uchar *src = mask.constScanLine(y);
367 for (
int x = 0; x < c.w; ++x) {
369 dest[x] = (src[x >> 3] & (1 << (7 - (x & 7)))) > 0 ? 255 : 0;
373 }
else if (mask.depth() == 8) {
374 for (
int y = 0; y < c.h; ++y) {
375 uchar *dest = d + (c.y + y) *dbpl + c.x;
377 const uchar *src = mask.constScanLine(y);
378 for (
int x = 0; x < c.w; ++x) {
390 int margin = m_current_fontengine ? m_current_fontengine->glyphMargin(m_format) : 0;
391 QPoint base(c.x + margin, c.y + margin + c.baseLineY-1);
392 if (m_image.rect().contains(base))
393 m_image.setPixel(base, 255);
394 m_image.save(QString::fromLatin1(
"cache-%1.png").arg(qint64(
this)));