21int QTextureGlyphCache::calculateSubPixelPositionCount(glyph_t glyph)
const
26 const int NumSubpixelPositions = 12;
28 QImage images[NumSubpixelPositions];
30 for (
int i = 0; i < NumSubpixelPositions; ++i) {
31 QImage img = textureMapForGlyph(glyph, QFixedPoint(QFixed::fromReal(i / 12.0), 0));
36 m_current_fontengine->addGlyphsToPath(&glyph, &point, 1, &path, QTextItem::RenderFlags());
42 images[numImages++] = std::move(img);
45 for (
int j = 0; j < numImages; ++j) {
46 if (images[j] == img) {
52 images[numImages++] = std::move(img);
59bool QTextureGlyphCache::populate(QFontEngine *fontEngine,
61 const glyph_t *glyphs,
62 const QFixedPoint *positions,
63 QPainter::RenderHints renderHints,
64 bool includeGlyphCacheScale)
67 printf(
"Populating with %lld glyphs\n",
static_cast<
long long>(numGlyphs));
68 qDebug() <<
" -> current transformation: " << m_transform;
71 m_current_fontengine = fontEngine;
72 const int padding = glyphPadding();
73 const int paddingDoubled = padding * 2;
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;
83 while (fontEngine->m_subPixelPositionCount == 0 && i < numGlyphs)
84 fontEngine->m_subPixelPositionCount = calculateSubPixelPositionCount(glyphs[i++]);
88 if (m_cx == 0 && m_cy == 0) {
93 qreal glyphCacheScaleX = transform().m11();
94 qreal glyphCacheScaleY = transform().m22();
96 QHash<GlyphAndSubPixelPosition, Coord> listItemCoordinates;
100 for (qsizetype i = 0; i < numGlyphs; ++i) {
101 const glyph_t glyph = glyphs[i];
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));
110 subPixelPosition = fontEngine->subPixelPositionFor(pos);
111 if (!verticalSubPixelPositions)
112 subPixelPosition.y = 0;
115 if (coords.contains(GlyphAndSubPixelPosition(glyph, subPixelPosition)))
117 if (listItemCoordinates.contains(GlyphAndSubPixelPosition(glyph, subPixelPosition)))
120 glyph_metrics_t metrics = fontEngine->alphaMapBoundingBox(glyph, subPixelPosition, m_transform, m_format);
123 printf(
"(%4x): w=%.2f, h=%.2f, xoff=%.2f, yoff=%.2f, x=%.2f, y=%.2f\n",
125 metrics.width.toReal(),
126 metrics.height.toReal(),
127 metrics.xoff.toReal(),
128 metrics.yoff.toReal(),
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) {
137 Coord c = { 0, 0, 0, 0, 0, 0 };
138 coords.insert(key, c);
142 if (m_format == QFontEngine::Format_Mono)
143 glyph_width = (glyph_width+7)&~7;
148 metrics.x.truncate(),
149 -metrics.y.truncate() };
151 listItemCoordinates.insert(key, c);
152 rowHeight = qMax(rowHeight, glyph_height);
154 if (listItemCoordinates.isEmpty())
157 rowHeight += paddingDoubled;
163 m_w = qNextPowerOfTwo(qCeil(fontEngine->maxCharWidth()) - 1);
167 QHash<GlyphAndSubPixelPosition, Coord>::iterator iter = listItemCoordinates.begin();
168 int requiredWidth = m_w;
169 while (iter != listItemCoordinates.end()) {
170 Coord c = iter.value();
172 m_currentRowHeight = qMax(m_currentRowHeight, c.h);
174 if (m_cx + c.w + padding > requiredWidth) {
175 int new_width = requiredWidth*2;
176 while (new_width < m_cx + c.w + padding)
178 if (new_width <= maxTextureWidth()) {
179 requiredWidth = new_width;
183 m_cy += m_currentRowHeight + paddingDoubled;
184 m_currentRowHeight = c.h;
188 if (maxTextureHeight() > 0 && m_cy + c.h + padding > maxTextureHeight()) {
196 coords.insert(iter.key(), c);
197 m_pendingGlyphs.insert(iter.key(), c);
199 m_cx += c.w + paddingDoubled;
206void QTextureGlyphCache::fillInPendingGlyphs()
208 if (!hasPendingGlyphs())
211 int requiredHeight = m_h;
212 int requiredWidth = m_w;
214 QHash<GlyphAndSubPixelPosition, Coord>::iterator iter = m_pendingGlyphs.begin();
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);
223 if (isNull() || requiredHeight > m_h || requiredWidth > m_w) {
225 createCache(qNextPowerOfTwo(requiredWidth - 1), qNextPowerOfTwo(requiredHeight - 1));
227 resizeCache(qNextPowerOfTwo(requiredWidth - 1), qNextPowerOfTwo(requiredHeight - 1));
232 QHash<GlyphAndSubPixelPosition, Coord>::iterator iter = m_pendingGlyphs.begin();
233 while (iter != m_pendingGlyphs.end()) {
234 GlyphAndSubPixelPosition key = iter.key();
235 fillTexture(iter.value(), key.glyph, key.subPixelPosition);
242 m_pendingGlyphs.clear();
273void QImageTextureGlyphCache::createTextureData(
int width,
int height)
276 case QFontEngine::Format_Mono:
277 m_image = QImage(width, height, QImage::Format_Mono);
279 case QFontEngine::Format_A8:
280 m_image = QImage(width, height, QImage::Format_Alpha8);
282 case QFontEngine::Format_A32:
283 m_image = QImage(width, height, QImage::Format_RGB32);
285 case QFontEngine::Format_ARGB:
286 m_image = QImage(width, height, QImage::Format_ARGB32_Premultiplied);
299void QImageTextureGlyphCache::fillTexture(
const Coord &c,
301 const QFixedPoint &subPixelPosition)
303 QImage mask = textureMapForGlyph(g, subPixelPosition);
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);
312 if (m_format == QFontEngine::Format_A32
313 || m_format == QFontEngine::Format_ARGB) {
314 QImage ref(m_image.bits() + (c.x * 4 + c.y * m_image.bytesPerLine()),
315 qMin(mask.width(), c.w), qMin(mask.height(), c.h), m_image.bytesPerLine(),
318 p.setCompositionMode(QPainter::CompositionMode_Source);
319 p.fillRect(0, 0, c.w, c.h, QColor(0,0,0,0));
320 p.drawImage(0, 0, mask);
322 }
else if (m_format == QFontEngine::Format_Mono) {
323 if (mask.depth() > 1) {
325 mask.convertTo(QImage::Format_Alpha8);
326 mask.reinterpretAsFormat(QImage::Format_Grayscale8);
328 mask.convertTo(QImage::Format_Mono, Qt::ThresholdDither);
331 int mw = qMin(mask.width(), c.w);
332 int mh = qMin(mask.height(), c.h);
333 uchar *d = m_image.bits();
334 qsizetype dbpl = m_image.bytesPerLine();
336 for (
int y = 0; y < c.h; ++y) {
337 uchar *dest = d + (c.y + y) *dbpl + c.x/8;
340 const uchar *src = mask.constScanLine(y);
341 for (
int x = 0; x < c.w/8; ++x) {
348 for (
int x = 0; x < c.w/8; ++x)
353 int mw = qMin(mask.width(), c.w);
354 int mh = qMin(mask.height(), c.h);
355 uchar *d = m_image.bits();
356 qsizetype dbpl = m_image.bytesPerLine();
358 if (mask.depth() == 1) {
359 for (
int y = 0; y < c.h; ++y) {
360 uchar *dest = d + (c.y + y) *dbpl + c.x;
362 const uchar *src = mask.constScanLine(y);
363 for (
int x = 0; x < c.w; ++x) {
365 dest[x] = (src[x >> 3] & (1 << (7 - (x & 7)))) > 0 ? 255 : 0;
369 }
else if (mask.depth() == 8) {
370 for (
int y = 0; y < c.h; ++y) {
371 uchar *dest = d + (c.y + y) *dbpl + c.x;
373 const uchar *src = mask.constScanLine(y);
374 for (
int x = 0; x < c.w; ++x) {
386 int margin = m_current_fontengine ? m_current_fontengine->glyphMargin(m_format) : 0;
387 QPoint base(c.x + margin, c.y + margin + c.baseLineY-1);
388 if (m_image.rect().contains(base))
389 m_image.setPixel(base, 255);
390 m_image.save(QString::fromLatin1(
"cache-%1.png").arg(qint64(
this)));