void QSGTextMaskMaterial::populate(const QPointF &p, const QVector<quint32> &glyphIndexes, const QVector<QPointF> &glyphPositions, QSGGeometry *geometry, QRectF *boundingRect, QPointF *baseLine, const QMargins &margins) { Q_ASSERT(m_font.isValid()); QVector<QFixedPoint> fixedPointPositions; for (int i=0; i<glyphPositions.size(); ++i) fixedPointPositions.append(QFixedPoint::fromPointF(glyphPositions.at(i))); QTextureGlyphCache *cache = glyphCache(); QRawFontPrivate *fontD = QRawFontPrivate::get(m_font); cache->populate(fontD->fontEngine, glyphIndexes.size(), glyphIndexes.constData(), fixedPointPositions.data()); cache->fillInPendingGlyphs(); int margin = fontD->fontEngine->glyphMargin(cache->glyphFormat()); qreal glyphCacheScaleX = cache->transform().m11(); qreal glyphCacheScaleY = cache->transform().m22(); qreal glyphCacheInverseScaleX = 1.0 / glyphCacheScaleX; qreal glyphCacheInverseScaleY = 1.0 / glyphCacheScaleY; Q_ASSERT(geometry->indexType() == GL_UNSIGNED_SHORT); geometry->allocate(glyphIndexes.size() * 4, glyphIndexes.size() * 6); QVector4D *vp = (QVector4D *)geometry->vertexDataAsTexturedPoint2D(); Q_ASSERT(geometry->sizeOfVertex() == sizeof(QVector4D)); ushort *ip = geometry->indexDataAsUShort(); QPointF position(p.x(), p.y() - m_font.ascent()); bool supportsSubPixelPositions = fontD->fontEngine->supportsSubPixelPositions(); for (int i=0; i<glyphIndexes.size(); ++i) { QFixed subPixelPosition; if (supportsSubPixelPositions) subPixelPosition = fontD->fontEngine->subPixelPositionForX(QFixed::fromReal(glyphPositions.at(i).x())); QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphIndexes.at(i), subPixelPosition); const QTextureGlyphCache::Coord &c = cache->coords.value(glyph); QPointF glyphPosition = glyphPositions.at(i) + position; // On a retina screen the glyph positions are not pre-scaled (as opposed to // eg. the raster paint engine). To ensure that we get the same behavior as // the raster engine (and CoreText itself) when it comes to rounding of the // coordinates, we need to apply the scale factor before rounding, and then // apply the inverse scale to get back to the coordinate system of the node. qreal x = (qFloor(glyphPosition.x() * glyphCacheScaleX) * glyphCacheInverseScaleX) + (c.baseLineX * glyphCacheInverseScaleX) - margin; qreal y = (qRound(glyphPosition.y() * glyphCacheScaleY) * glyphCacheInverseScaleY) - (c.baseLineY * glyphCacheInverseScaleY) - margin; qreal w = c.w * glyphCacheInverseScaleX; qreal h = c.h * glyphCacheInverseScaleY; *boundingRect |= QRectF(x + margin, y + margin, w, h); float cx1 = x - margins.left(); float cx2 = x + w + margins.right(); float cy1 = y - margins.top(); float cy2 = y + h + margins.bottom(); float tx1 = c.x - margins.left(); float tx2 = c.x + c.w + margins.right(); float ty1 = c.y - margins.top(); float ty2 = c.y + c.h + margins.bottom(); if (baseLine->isNull()) *baseLine = glyphPosition; vp[4 * i + 0] = QVector4D(cx1, cy1, tx1, ty1); vp[4 * i + 1] = QVector4D(cx2, cy1, tx2, ty1); vp[4 * i + 2] = QVector4D(cx1, cy2, tx1, ty2); vp[4 * i + 3] = QVector4D(cx2, cy2, tx2, ty2); int o = i * 4; ip[6 * i + 0] = o + 0; ip[6 * i + 1] = o + 2; ip[6 * i + 2] = o + 3; ip[6 * i + 3] = o + 3; ip[6 * i + 4] = o + 1; ip[6 * i + 5] = o + 0; } }
void QSGTextMaskMaterial::populate(const QPointF &p, const QVector<quint32> &glyphIndexes, const QVector<QPointF> &glyphPositions, QSGGeometry *geometry, QRectF *boundingRect, QPointF *baseLine, const QMargins &margins) { Q_ASSERT(m_font.isValid()); QVector<QFixedPoint> fixedPointPositions; for (int i=0; i<glyphPositions.size(); ++i) fixedPointPositions.append(QFixedPoint::fromPointF(glyphPositions.at(i))); QTextureGlyphCache *cache = glyphCache(); QRawFontPrivate *fontD = QRawFontPrivate::get(m_font); cache->populate(fontD->fontEngine, glyphIndexes.size(), glyphIndexes.constData(), fixedPointPositions.data()); cache->fillInPendingGlyphs(); int margin = fontD->fontEngine->glyphMargin(cache->cacheType()); Q_ASSERT(geometry->indexType() == GL_UNSIGNED_SHORT); geometry->allocate(glyphIndexes.size() * 4, glyphIndexes.size() * 6); QVector4D *vp = (QVector4D *)geometry->vertexDataAsTexturedPoint2D(); Q_ASSERT(geometry->sizeOfVertex() == sizeof(QVector4D)); ushort *ip = geometry->indexDataAsUShort(); QPointF position(p.x(), p.y() - m_font.ascent()); bool supportsSubPixelPositions = fontD->fontEngine->supportsSubPixelPositions(); for (int i=0; i<glyphIndexes.size(); ++i) { QFixed subPixelPosition; if (supportsSubPixelPositions) subPixelPosition = fontD->fontEngine->subPixelPositionForX(QFixed::fromReal(glyphPositions.at(i).x())); QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphIndexes.at(i), subPixelPosition); const QTextureGlyphCache::Coord &c = cache->coords.value(glyph); QPointF glyphPosition = glyphPositions.at(i) + position; int x = qFloor(glyphPosition.x()) + c.baseLineX - margin; int y = qFloor(glyphPosition.y()) - c.baseLineY - margin; *boundingRect |= QRectF(x + margin, y + margin, c.w, c.h); float cx1 = x - margins.left(); float cx2 = x + c.w + margins.right(); float cy1 = y - margins.top(); float cy2 = y + c.h + margins.bottom(); float tx1 = c.x - margins.left(); float tx2 = c.x + c.w + margins.right(); float ty1 = c.y - margins.top(); float ty2 = c.y + c.h + margins.bottom(); if (baseLine->isNull()) *baseLine = glyphPosition; vp[4 * i + 0] = QVector4D(cx1, cy1, tx1, ty1); vp[4 * i + 1] = QVector4D(cx2, cy1, tx2, ty1); vp[4 * i + 2] = QVector4D(cx1, cy2, tx1, ty2); vp[4 * i + 3] = QVector4D(cx2, cy2, tx2, ty2); int o = i * 4; ip[6 * i + 0] = o + 0; ip[6 * i + 1] = o + 2; ip[6 * i + 2] = o + 3; ip[6 * i + 3] = o + 3; ip[6 * i + 4] = o + 1; ip[6 * i + 5] = o + 0; } }