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;
213 const int padding = glyphPadding();
215 QHash<GlyphAndSubPixelPosition, Coord>::iterator iter = m_pendingGlyphs.begin();
216 while (iter != m_pendingGlyphs.end()) {
217 Coord c = iter.value();
218 requiredHeight = qMax(requiredHeight, c.y + c.h + padding);
219 requiredWidth = qMax(requiredWidth, c.x + c.w + padding);
224 if (isNull() || requiredHeight > m_h || requiredWidth > m_w) {
226 createCache(qNextPowerOfTwo(requiredWidth - 1), qNextPowerOfTwo(requiredHeight - 1));
228 resizeCache(qNextPowerOfTwo(requiredWidth - 1), qNextPowerOfTwo(requiredHeight - 1));
233 QHash<GlyphAndSubPixelPosition, Coord>::iterator iter = m_pendingGlyphs.begin();
234 while (iter != m_pendingGlyphs.end()) {
235 GlyphAndSubPixelPosition key = iter.key();
236 fillTexture(iter.value(), key.glyph, key.subPixelPosition);
243 m_pendingGlyphs.clear();
274void QImageTextureGlyphCache::createTextureData(
int width,
int height)
277 case QFontEngine::Format_Mono:
278 m_image = QImage(width, height, QImage::Format_Mono);
280 case QFontEngine::Format_A8:
281 m_image = QImage(width, height, QImage::Format_Alpha8);
283 case QFontEngine::Format_A32:
284 m_image = QImage(width, height, QImage::Format_RGB32);
286 case QFontEngine::Format_ARGB:
287 m_image = QImage(width, height, QImage::Format_ARGB32_Premultiplied);
300void QImageTextureGlyphCache::fillTexture(
const Coord &c,
302 const QFixedPoint &subPixelPosition)
304 QImage mask = textureMapForGlyph(g, subPixelPosition);
309 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());
310 if (mask.width() > c.w || mask.height() > c.h) {
311 printf(
" ERROR; mask is bigger than reserved space! %dx%d instead of %dx%d\n", mask.width(), mask.height(), c.w,c.h);
315 if (m_format == QFontEngine::Format_A32
316 || m_format == QFontEngine::Format_ARGB) {
317 QImage ref(m_image.bits() + (c.x * 4 + c.y * m_image.bytesPerLine()),
318 qMin(mask.width(), c.w), qMin(mask.height(), c.h), m_image.bytesPerLine(),
321 p.setCompositionMode(QPainter::CompositionMode_Source);
322 p.fillRect(0, 0, c.w, c.h, QColor(0,0,0,0));
323 p.drawImage(0, 0, mask);
325 }
else if (m_format == QFontEngine::Format_Mono) {
326 if (mask.depth() > 1) {
328 mask.convertTo(QImage::Format_Alpha8);
329 mask.reinterpretAsFormat(QImage::Format_Grayscale8);
331 mask.convertTo(QImage::Format_Mono, Qt::ThresholdDither);
334 int mw = qMin(mask.width(), c.w);
335 int mh = qMin(mask.height(), c.h);
336 uchar *d = m_image.bits();
337 qsizetype dbpl = m_image.bytesPerLine();
339 for (
int y = 0; y < c.h; ++y) {
340 uchar *dest = d + (c.y + y) *dbpl + c.x/8;
343 const uchar *src = mask.constScanLine(y);
344 for (
int x = 0; x < c.w/8; ++x) {
351 for (
int x = 0; x < c.w/8; ++x)
356 int mw = qMin(mask.width(), c.w);
357 int mh = qMin(mask.height(), c.h);
358 uchar *d = m_image.bits();
359 qsizetype dbpl = m_image.bytesPerLine();
361 if (mask.depth() == 1) {
362 for (
int y = 0; y < c.h; ++y) {
363 uchar *dest = d + (c.y + y) *dbpl + c.x;
365 const uchar *src = mask.constScanLine(y);
366 for (
int x = 0; x < c.w; ++x) {
368 dest[x] = (src[x >> 3] & (1 << (7 - (x & 7)))) > 0 ? 255 : 0;
372 }
else if (mask.depth() == 8) {
373 for (
int y = 0; y < c.h; ++y) {
374 uchar *dest = d + (c.y + y) *dbpl + c.x;
376 const uchar *src = mask.constScanLine(y);
377 for (
int x = 0; x < c.w; ++x) {
389 int margin = m_current_fontengine ? m_current_fontengine->glyphMargin(m_format) : 0;
390 QPoint base(c.x + margin, c.y + margin + c.baseLineY-1);
391 if (m_image.rect().contains(base))
392 m_image.setPixel(base, 255);
393 m_image.save(QString::fromLatin1(
"cache-%1.png").arg(qint64(
this)));