267 Q_Q(QOpenGL2PaintEngineEx);
269 Qt::BrushStyle style = currentBrush.style();
271 bool smoothPixmapTransform = q->state()->renderHints & QPainter::SmoothPixmapTransform;
272 GLenum filterMode = smoothPixmapTransform ? GL_LINEAR : GL_NEAREST;
274 if ( (style >= Qt::Dense1Pattern) && (style <= Qt::DiagCrossPattern) ) {
276 QImage textureImage = qt_imageForBrush(style,
false);
280 else if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern) {
283 const QGradient *gradient = currentBrush.gradient();
285 GLenum wrapMode = GL_CLAMP_TO_EDGE;
286 if (gradient->spread() == QGradient::RepeatSpread || gradient->type() == QGradient::ConicalGradient)
287 wrapMode = GL_REPEAT;
288 else if (gradient->spread() == QGradient::ReflectSpread)
289 wrapMode = GL_MIRRORED_REPEAT;
293 else if (style == Qt::TexturePattern) {
294 currentBrushImage = currentBrush.textureImage();
296 int max_texture_size = ctx->d_func()->maxTextureSize();
297 QSize newSize = currentBrushImage.size();
298 newSize = newSize.boundedTo(QSize(max_texture_size, max_texture_size));
299 if (!QOpenGLContext::currentContext()->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextureRepeat)) {
300 if (!isPowerOfTwo(newSize.width()) || !isPowerOfTwo(newSize.height())) {
301 newSize.setHeight(qNextPowerOfTwo(newSize.height() - 1));
302 newSize.setWidth(qNextPowerOfTwo(newSize.width() - 1));
305 if (currentBrushImage.size() != newSize)
306 currentBrushImage = currentBrushImage.scaled(newSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
308 GLuint wrapMode = GL_REPEAT;
319 Qt::BrushStyle style = currentBrush.style();
321 if (style == Qt::NoBrush)
324 QTransform brushQTransform = currentBrush.transform();
325 bool isCosmetic =
false;
327 if (style == Qt::SolidPattern) {
328 QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity);
329 shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::FragmentColor), col);
333 QPointF translationPoint;
335 if (style <= Qt::DiagCrossPattern) {
336 QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity);
338 shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::PatternColor), col);
341 shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::HalfViewportSize), halfViewportSize);
343 isCosmetic = !q->painter()->testRenderHint(QPainter::NonCosmeticBrushPatterns);
345 else if (style == Qt::LinearGradientPattern) {
346 const QLinearGradient *g =
static_cast<
const QLinearGradient *>(currentBrush.gradient());
348 QPointF realStart = g->start();
349 QPointF realFinal = g->finalStop();
350 translationPoint = realStart;
352 QPointF l = realFinal - realStart;
354 QVector3D linearData(
357 1.0f / (l.x() * l.x() + l.y() * l.y())
360 shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::LinearData), linearData);
363 shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::HalfViewportSize), halfViewportSize);
365 else if (style == Qt::ConicalGradientPattern) {
366 const QConicalGradient *g =
static_cast<
const QConicalGradient *>(currentBrush.gradient());
367 translationPoint = g->center();
369 GLfloat angle = -qDegreesToRadians(g->angle());
371 shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::Angle), angle);
374 shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::HalfViewportSize), halfViewportSize);
376 else if (style == Qt::RadialGradientPattern) {
377 const QRadialGradient *g =
static_cast<
const QRadialGradient *>(currentBrush.gradient());
378 QPointF realCenter = g->center();
379 QPointF realFocal = g->focalPoint();
380 qreal realRadius = g->centerRadius() - g->focalRadius();
381 translationPoint = realFocal;
383 QPointF fmp = realCenter - realFocal;
384 shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::Fmp), fmp);
386 GLfloat fmp2_m_radius2 = -fmp.x() * fmp.x() - fmp.y() * fmp.y() + realRadius*realRadius;
387 shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::Fmp2MRadius2), fmp2_m_radius2);
388 shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::Inverse2Fmp2MRadius2),
389 GLfloat(1.0 / (2.0*fmp2_m_radius2)));
390 shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::SqrFr),
391 GLfloat(g->focalRadius() * g->focalRadius()));
392 shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::BRadius),
393 GLfloat(2 * (g->centerRadius() - g->focalRadius()) * g->focalRadius()),
395 g->centerRadius() - g->focalRadius());
398 shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::HalfViewportSize), halfViewportSize);
400 else if (style == Qt::TexturePattern) {
401 const QPixmap& texPixmap = currentBrush.texture();
403 if (qHasPixmapTexture(currentBrush) && currentBrush.texture().isQBitmap()) {
404 QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity);
405 shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::PatternColor), col);
408 QSizeF invertedTextureSize(1.0 / texPixmap.width(), 1.0 / texPixmap.height());
409 shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::InvertedTextureSize), invertedTextureSize);
412 shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::HalfViewportSize), halfViewportSize);
415 qWarning(
"QOpenGL2PaintEngineEx: Unimplemented fill style");
417 const QPointF &brushOrigin = q->state()->brushOrigin;
420 matrix = q->state()->matrix;
421 matrix.translate(brushOrigin.x(), brushOrigin.y());
423 matrix = brushQTransform * matrix;
425 QTransform translate(1, 0, 0, 1, -translationPoint.x(), -translationPoint.y());
428 if (device->paintFlipped()) {
432 QTransform gl_to_qt(1, 0, 0, m22, 0, dy);
433 QTransform inv_matrix = gl_to_qt * matrix.inverted() * translate;
435 shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::BrushTransform), inv_matrix);
436 shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::BrushTexture),
QT_BRUSH_TEXTURE_UNIT);
519 if (ctx->functions()->hasOpenGLFeature(QOpenGLFunctions::BlendEquationAdvanced)) {
520 if (q->state()->composition_mode <= QPainter::CompositionMode_Plus) {
522 funcs.glBlendEquation(GL_FUNC_ADD);
526 shaderManager->setCompositionMode(q->state()->composition_mode);
528 if (q->state()->composition_mode > QPainter::CompositionMode_Plus) {
529 qWarning(
"Unsupported composition mode");
534 switch(q->state()->composition_mode) {
535 case QPainter::CompositionMode_SourceOver:
536 funcs.glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
538 case QPainter::CompositionMode_DestinationOver:
539 funcs.glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE);
541 case QPainter::CompositionMode_Clear:
542 funcs.glBlendFunc(GL_ZERO, GL_ZERO);
544 case QPainter::CompositionMode_Source:
545 funcs.glBlendFunc(GL_ONE, GL_ZERO);
547 case QPainter::CompositionMode_Destination:
548 funcs.glBlendFunc(GL_ZERO, GL_ONE);
550 case QPainter::CompositionMode_SourceIn:
551 funcs.glBlendFunc(GL_DST_ALPHA, GL_ZERO);
553 case QPainter::CompositionMode_DestinationIn:
554 funcs.glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
556 case QPainter::CompositionMode_SourceOut:
557 funcs.glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ZERO);
559 case QPainter::CompositionMode_DestinationOut:
560 funcs.glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
562 case QPainter::CompositionMode_SourceAtop:
563 funcs.glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
565 case QPainter::CompositionMode_DestinationAtop:
566 funcs.glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA);
568 case QPainter::CompositionMode_Xor:
569 funcs.glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
571 case QPainter::CompositionMode_Plus:
572 funcs.glBlendFunc(GL_ONE, GL_ONE);
574 case QPainter::CompositionMode_Multiply:
577 case QPainter::CompositionMode_Screen:
580 case QPainter::CompositionMode_Overlay:
583 case QPainter::CompositionMode_Darken:
586 case QPainter::CompositionMode_Lighten:
589 case QPainter::CompositionMode_ColorDodge:
592 case QPainter::CompositionMode_ColorBurn:
595 case QPainter::CompositionMode_HardLight:
598 case QPainter::CompositionMode_SoftLight:
601 case QPainter::CompositionMode_Difference:
604 case QPainter::CompositionMode_Exclusion:
608 qWarning(
"Unsupported composition mode");
849 if (currentBrush.style() > Qt::SolidPattern)
853 const bool supportsElementIndexUint = funcs.hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint);
855 const QPointF*
const points =
reinterpret_cast<
const QPointF*>(path.points());
858 if (path.shape() == QVectorPath::RectangleHint) {
859 QOpenGLRect rect(points[0].x(), points[0].y(), points[2].x(), points[2].y());
860 prepareForDraw(currentBrush.isOpaque());
862 }
else if (path.isConvex()) {
864 if (path.isCacheable()) {
865 QVectorPath::CacheEntry *data = path.lookupCacheData(q);
866 QOpenGL2PEVectorPathCache *cache;
868 bool updateCache =
false;
871 cache = (QOpenGL2PEVectorPathCache *) data->data;
873 qreal scaleFactor = cache->iscale / inverseScale;
874 if (scaleFactor < 0.5 || scaleFactor > 2.0) {
875#ifdef QT_OPENGL_CACHE_AS_VBOS
876 glDeleteBuffers(1, &cache->vbo);
878 Q_ASSERT(cache->ibo == 0);
880 free(cache->vertices);
881 Q_ASSERT(cache->indices ==
nullptr);
886 cache =
new QOpenGL2PEVectorPathCache;
887 data =
const_cast<QVectorPath &>(path).addCacheData(q, cache, cleanupVectorPath);
893 vertexCoordinateArray.clear();
894 vertexCoordinateArray.addPath(path, inverseScale,
false);
895 int vertexCount = vertexCoordinateArray.vertexCount();
896 int floatSizeInBytes = vertexCount * 2 *
sizeof(
float);
897 cache->vertexCount = vertexCount;
898 cache->indexCount = 0;
899 cache->primitiveType = GL_TRIANGLE_FAN;
900 cache->iscale = inverseScale;
901#ifdef QT_OPENGL_CACHE_AS_VBOS
902 funcs.glGenBuffers(1, &cache->vbo);
903 funcs.glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
904 funcs.glBufferData(GL_ARRAY_BUFFER, floatSizeInBytes, vertexCoordinateArray.data(), GL_STATIC_DRAW);
907 cache->vertices = (
float *) malloc(floatSizeInBytes);
908 memcpy(cache->vertices, vertexCoordinateArray.data(), floatSizeInBytes);
909 cache->indices =
nullptr;
913 prepareForDraw(currentBrush.isOpaque());
914#ifdef QT_OPENGL_CACHE_AS_VBOS
915 funcs.glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
916 uploadData(QT_VERTEX_COORD_ATTR, 0, cache->vertexCount);
917 setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, 0);
919 uploadData(QT_VERTEX_COORDS_ATTR, cache->vertices, cache->vertexCount * 2);
921 funcs.glDrawArrays(cache->primitiveType, 0, cache->vertexCount);
926 path.makeCacheable();
927 vertexCoordinateArray.clear();
928 vertexCoordinateArray.addPath(path, inverseScale,
false);
929 prepareForDraw(currentBrush.isOpaque());
930 drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN);
934 bool useCache = path.isCacheable();
936 QRectF bbox = path.controlPointRect();
938 useCache &= (bbox.left() > -0x8000 * inverseScale)
939 && (bbox.right() < 0x8000 * inverseScale)
940 && (bbox.top() > -0x8000 * inverseScale)
941 && (bbox.bottom() < 0x8000 * inverseScale);
945 QVectorPath::CacheEntry *data = path.lookupCacheData(q);
946 QOpenGL2PEVectorPathCache *cache;
948 bool updateCache =
false;
951 cache = (QOpenGL2PEVectorPathCache *) data->data;
953 qreal scaleFactor = cache->iscale / inverseScale;
954 if (scaleFactor < 0.5 || scaleFactor > 2.0) {
955#ifdef QT_OPENGL_CACHE_AS_VBOS
956 glDeleteBuffers(1, &cache->vbo);
957 glDeleteBuffers(1, &cache->ibo);
959 free(cache->vertices);
960 free(cache->indices);
965 cache =
new QOpenGL2PEVectorPathCache;
966 data =
const_cast<QVectorPath &>(path).addCacheData(q, cache, cleanupVectorPath);
972 QTriangleSet polys = qTriangulate(path, QTransform().scale(1 / inverseScale, 1 / inverseScale), 1, supportsElementIndexUint);
973 cache->vertexCount = polys.vertices.size() / 2;
974 cache->indexCount = polys.indices.size();
975 cache->primitiveType = GL_TRIANGLES;
976 cache->iscale = inverseScale;
977 cache->indexType = polys.indices.type();
978#ifdef QT_OPENGL_CACHE_AS_VBOS
979 funcs.glGenBuffers(1, &cache->vbo);
980 funcs.glGenBuffers(1, &cache->ibo);
981 funcs.glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
982 funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cache->ibo);
984 if (polys.indices.type() == QVertexIndexVector::UnsignedInt)
985 funcs.glBufferData(GL_ELEMENT_ARRAY_BUFFER,
sizeof(quint32) * polys.indices.size(), polys.indices.data(), GL_STATIC_DRAW);
987 funcs.glBufferData(GL_ELEMENT_ARRAY_BUFFER,
sizeof(quint16) * polys.indices.size(), polys.indices.data(), GL_STATIC_DRAW);
989 QVarLengthArray<
float> vertices(polys.vertices.size());
990 for (
int i = 0; i < polys.vertices.size(); ++i)
991 vertices[i] =
float(inverseScale * polys.vertices.at(i));
992 funcs.glBufferData(GL_ARRAY_BUFFER,
sizeof(
float) * vertices.size(), vertices.data(), GL_STATIC_DRAW);
994 cache->vertices = (
float *) malloc(
sizeof(
float) * polys.vertices.size());
995 if (polys.indices.type() == QVertexIndexVector::UnsignedInt) {
996 cache->indices = (quint32 *) malloc(
sizeof(quint32) * polys.indices.size());
997 memcpy(cache->indices, polys.indices.data(),
sizeof(quint32) * polys.indices.size());
999 cache->indices = (quint16 *) malloc(
sizeof(quint16) * polys.indices.size());
1000 memcpy(cache->indices, polys.indices.data(),
sizeof(quint16) * polys.indices.size());
1002 for (
int i = 0; i < polys.vertices.size(); ++i)
1003 cache->vertices[i] =
float(inverseScale * polys.vertices.at(i));
1007 prepareForDraw(currentBrush.isOpaque());
1008#ifdef QT_OPENGL_CACHE_AS_VBOS
1009 funcs.glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
1010 funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cache->ibo);
1011 uploadData(QT_VERTEX_COORDS_ATTR, 0, cache->vertexCount);
1012 setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, 0);
1013 if (cache->indexType == QVertexIndexVector::UnsignedInt)
1014 funcs.glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_INT, 0);
1016 funcs.glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_SHORT, 0);
1017 funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1018 funcs.glBindBuffer(GL_ARRAY_BUFFER, 0);
1020 uploadData(QT_VERTEX_COORDS_ATTR, cache->vertices, cache->vertexCount * 2);
1021 const GLenum indexValueType = cache->indexType == QVertexIndexVector::UnsignedInt ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
1022 const bool useIndexVbo = uploadIndexData(cache->indices, indexValueType, cache->indexCount);
1023 funcs.glDrawElements(cache->primitiveType, cache->indexCount, indexValueType, useIndexVbo ?
nullptr : cache->indices);
1029 path.makeCacheable();
1031 if (device->context()->format().stencilBufferSize() <= 0) {
1034 QRectF bbox = path.controlPointRect();
1036 bool withinLimits = (bbox.left() > -0x8000 * inverseScale)
1037 && (bbox.right() < 0x8000 * inverseScale)
1038 && (bbox.top() > -0x8000 * inverseScale)
1039 && (bbox.bottom() < 0x8000 * inverseScale);
1041 QTriangleSet polys = qTriangulate(path, QTransform().scale(1 / inverseScale, 1 / inverseScale), 1, supportsElementIndexUint);
1043 QVarLengthArray<
float> vertices(polys.vertices.size());
1044 for (
int i = 0; i < polys.vertices.size(); ++i)
1045 vertices[i] =
float(inverseScale * polys.vertices.at(i));
1047 prepareForDraw(currentBrush.isOpaque());
1048 uploadData(QT_VERTEX_COORDS_ATTR, vertices.constData(), vertices.size());
1049 const GLenum indexValueType = funcs.hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
1050 const bool useIndexVbo = uploadIndexData(polys.indices.data(), indexValueType, polys.indices.size());
1051 funcs.glDrawElements(GL_TRIANGLES, polys.indices.size(), indexValueType, useIndexVbo ?
nullptr : polys.indices.data());
1054 qWarning(
"Painter path exceeds +/-32767 pixels.");
1060 vertexCoordinateArray.clear();
1061 vertexCoordinateArray.addPath(path, inverseScale,
false);
1063 fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill());
1065 funcs.glStencilMask(0xff);
1066 funcs.glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
1068 if (q->state()->clipTestEnabled) {
1071 }
else if (path.hasWindingFill()) {
1073 funcs.glStencilFunc(GL_NOTEQUAL, 0, 0xff);
1078 prepareForDraw(currentBrush.isOpaque());
1081 composite(vertexCoordinateArray.boundingRect());
1082 funcs.glStencilMask(0);
1093 const QOpenGLRect &bounds,
1094 StencilFillMode mode)
1096 Q_ASSERT(count || stops);
1099 funcs.glStencilMask(0xff);
1101 if (dirtyStencilRegion.intersects(currentScissorBounds)) {
1102 const QRegion clearRegion = dirtyStencilRegion.intersected(currentScissorBounds);
1103 funcs.glClearStencil(0);
1104 for (
const QRect &rect : clearRegion) {
1105#ifndef QT_GL_NO_SCISSOR_TEST
1108 funcs.glClear(GL_STENCIL_BUFFER_BIT);
1111 dirtyStencilRegion -= currentScissorBounds;
1113#ifndef QT_GL_NO_SCISSOR_TEST
1118 funcs.glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1121 if (ctx->format().stencilBufferSize() <= 0)
1122 qWarning(
"OpenGL paint engine: attempted to use stencil test without requesting a stencil buffer.");
1124 funcs.glEnable(GL_STENCIL_TEST);
1126 if (mode == WindingFillMode) {
1127 Q_ASSERT(stops && !count);
1128 if (q->state()->clipTestEnabled) {
1131 funcs.glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
1137 funcs.glStencilFunc(GL_ALWAYS, 0, 0xff);
1138 funcs.glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
1143 funcs.glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_INCR_WRAP, GL_INCR_WRAP);
1145 funcs.glStencilOpSeparate(GL_BACK, GL_KEEP, GL_DECR_WRAP, GL_DECR_WRAP);
1147 drawVertexArrays(data, stops, stopCount, GL_TRIANGLE_FAN);
1149 if (q->state()->clipTestEnabled) {
1152 funcs.glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
1156 }
else if (mode == OddEvenFillMode) {
1158 funcs.glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT);
1159 drawVertexArrays(data, stops, stopCount, GL_TRIANGLE_FAN);
1162 Q_ASSERT(count && !stops);
1165 funcs.glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT);
1166 setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, data);
1167 funcs.glDrawArrays(GL_TRIANGLE_STRIP, 0, count);
1170 funcs.glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
1171 if (q->state()->clipTestEnabled) {
1178 uploadData(QT_VERTEX_COORDS_ATTR, data, count * 2);
1179 funcs.glDrawArrays(GL_TRIANGLE_STRIP, 0, count);
1184 funcs.glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1383 const Qt::PenStyle penStyle = qpen_style(pen);
1384 const QBrush &penBrush = qpen_brush(pen);
1385 const bool opaque = penBrush.isOpaque() && s->opacity > 0.99;
1394 QRectF clip = q->state()->matrix.inverted().mapRect(q->state()->clipEnabled
1395 ? q->state()->rectangleClip
1396 : QRectF(0, 0, width, height));
1398 if (penStyle == Qt::SolidLine) {
1399 stroker.process(path, pen, clip, s->renderHints);
1402 dasher.process(path, pen, clip, s->renderHints);
1404 QVectorPath dashStroke(dasher.points(),
1405 dasher.elementCount(),
1406 dasher.elementTypes());
1407 stroker.process(dashStroke, pen, clip, s->renderHints);
1410 if (!stroker.vertexCount())
1416 uploadData(QT_VERTEX_COORDS_ATTR, stroker.vertices(), stroker.vertexCount());
1417 funcs.glDrawArrays(GL_TRIANGLE_STRIP, 0, stroker.vertexCount() / 2);
1419 qreal width = qpen_widthf(pen) / 2;
1422 qreal extra = pen.joinStyle() == Qt::MiterJoin
1423 ? qMax(pen.miterLimit() * width, width)
1426 if (pen.isCosmetic())
1427 extra = extra * inverseScale;
1429 QRectF bounds = path.controlPointRect().adjusted(-extra, -extra, extra, extra);
1431 fillStencilWithVertexArray(stroker.vertices(), stroker.vertexCount() / 2,
1432 nullptr, 0, bounds, QOpenGL2PaintEngineExPrivate::TriStripStrokeFillMode);
1434 funcs.glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
1443 funcs.glStencilMask(0);
1551void QOpenGL2PaintEngineEx::drawImage(
const QRectF& dest,
const QImage& image,
const QRectF& src,
1552 Qt::ImageConversionFlags)
1554 Q_D(QOpenGL2PaintEngineEx);
1555 QOpenGLContext *ctx = d->ctx;
1557 int max_texture_size = ctx->d_func()->maxTextureSize();
1558 if (image.width() > max_texture_size || image.height() > max_texture_size) {
1559 QImage scaled = image.scaled(max_texture_size, max_texture_size, Qt::KeepAspectRatio);
1561 const qreal sx = scaled.width() / qreal(image.width());
1562 const qreal sy = scaled.height() / qreal(image.height());
1564 drawImage(dest, scaled, scaleRect(src, sx, sy));
1569 d->transferMode(ImageDrawingMode);
1571 QOpenGLTextureUploader::BindOptions bindOption = QOpenGLTextureUploader::PremultipliedAlphaBindOption;
1573 switch (image.format()) {
1574 case QImage::Format_RGBA8888:
1575 case QImage::Format_ARGB32:
1576 case QImage::Format_RGBA64:
1577 case QImage::Format_RGBA16FPx4:
1578 case QImage::Format_RGBA32FPx4:
1579 d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::NonPremultipliedImageSrc);
1582 case QImage::Format_Alpha8:
1583 if (ctx->functions()->hasOpenGLFeature(QOpenGLFunctions::TextureRGFormats)) {
1584 d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::AlphaImageSrc);
1585 bindOption = QOpenGLTextureUploader::UseRedForAlphaAndLuminanceBindOption;
1587 d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::ImageSrc);
1589 case QImage::Format_Grayscale8:
1590 case QImage::Format_Grayscale16:
1591 if (ctx->functions()->hasOpenGLFeature(QOpenGLFunctions::TextureRGFormats)) {
1592 d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::GrayscaleImageSrc);
1593 bindOption = QOpenGLTextureUploader::UseRedForAlphaAndLuminanceBindOption;
1595 d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::ImageSrc);
1598 d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::ImageSrc);
1602 ImageWithBindOptions imageWithOptions = { image, bindOption };
1603 GLenum filterMode = state()->renderHints & QPainter::SmoothPixmapTransform ? GL_LINEAR : GL_NEAREST;
1606 d->drawTexture(dest, src, image.size(), !image.hasAlphaChannel());
1761 QStaticTextItem *staticTextItem)
1763 Q_Q(QOpenGL2PaintEngineEx);
1767 void *cacheKey = ctx;
1768 bool recreateVertexArrays =
false;
1770 QTransform glyphCacheTransform;
1771 QFontEngine *fe = staticTextItem->fontEngine();
1772 if (fe->supportsTransformation(s->matrix)) {
1776 glyphCacheTransform = s->matrix.type() < QTransform::TxRotate ?
1777 QTransform::fromScale(qAbs(s->matrix.m11()), qAbs(s->matrix.m22())) :
1778 QTransform::fromScale(
1779 QVector2D(s->matrix.m11(), s->matrix.m12()).length(),
1780 QVector2D(s->matrix.m21(), s->matrix.m22()).length());
1783 QOpenGLTextureGlyphCache *cache =
1784 (QOpenGLTextureGlyphCache *) fe->glyphCache(cacheKey, glyphFormat, glyphCacheTransform);
1785 if (!cache || cache->glyphFormat() != glyphFormat || cache->contextGroup() ==
nullptr) {
1786 cache =
new QOpenGLTextureGlyphCache(glyphFormat, glyphCacheTransform);
1787 fe->setGlyphCache(cacheKey, cache);
1788 recreateVertexArrays =
true;
1791 if (staticTextItem->userDataNeedsUpdate) {
1792 recreateVertexArrays =
true;
1793 }
else if (staticTextItem->userData() ==
nullptr) {
1794 recreateVertexArrays =
true;
1795 }
else if (staticTextItem->userData()->type != QStaticTextUserData::OpenGLUserData) {
1796 recreateVertexArrays =
true;
1798 QOpenGLStaticTextUserData *userData =
static_cast<QOpenGLStaticTextUserData *>(staticTextItem->userData());
1799 if (userData->glyphFormat != glyphFormat) {
1800 recreateVertexArrays =
true;
1801 }
else if (userData->cacheSerialNumber != cache->serialNumber()) {
1802 recreateVertexArrays =
true;
1809 if (recreateVertexArrays) {
1810 cache->setPaintEnginePrivate(
this);
1811 if (!cache->populate(fe, staticTextItem->numGlyphs,
1812 staticTextItem->glyphs, staticTextItem->glyphPositions,
1816 cache->populate(fe, staticTextItem->numGlyphs,
1817 staticTextItem->glyphs, staticTextItem->glyphPositions,
1821 if (cache->hasPendingGlyphs()) {
1828 activateTextureUnit(glypchCacheTextureUnit);
1830 cache->fillInPendingGlyphs();
1833 lastTextureUsed = cache->texture();
1839 cache->setPaintEnginePrivate(
nullptr);
1842 if (cache->width() == 0 || cache->height() == 0)
1845 if (glyphFormat == QFontEngine::Format_ARGB)
1850 int margin = fe->glyphMargin(glyphFormat);
1852 GLfloat dx = 1.0 / cache->width();
1853 GLfloat dy = 1.0 / cache->height();
1856 QOpenGL2PEXVertexArray *vertexCoordinates = &vertexCoordinateArray;
1857 QOpenGL2PEXVertexArray *textureCoordinates = &textureCoordinateArray;
1859 if (staticTextItem->useBackendOptimizations) {
1860 QOpenGLStaticTextUserData *userData =
nullptr;
1862 if (staticTextItem->userData() ==
nullptr
1863 || staticTextItem->userData()->type != QStaticTextUserData::OpenGLUserData) {
1865 userData =
new QOpenGLStaticTextUserData();
1866 staticTextItem->setUserData(userData);
1869 userData =
static_cast<QOpenGLStaticTextUserData*>(staticTextItem->userData());
1872 userData->glyphFormat = glyphFormat;
1873 userData->cacheSerialNumber = cache->serialNumber();
1876 vertexCoordinates = &userData->vertexCoordinateArray;
1877 textureCoordinates = &userData->textureCoordinateArray;
1879 QSize size(cache->width(), cache->height());
1880 if (userData->cacheSize != size) {
1881 recreateVertexArrays =
true;
1882 userData->cacheSize = size;
1886 if (recreateVertexArrays) {
1887 vertexCoordinates->clear();
1888 textureCoordinates->clear();
1890 bool supportsSubPixelPositions = fe->supportsSubPixelPositions();
1891 bool verticalSubPixelPositions = fe->supportsVerticalSubPixelPositions()
1892 && (s->renderHints & QPainter::VerticalSubpixelPositioning) != 0;
1893 for (
int i=0; i<staticTextItem->numGlyphs; ++i) {
1894 QFixedPoint subPixelPosition;
1895 if (supportsSubPixelPositions) {
1896 subPixelPosition = fe->subPixelPositionFor(staticTextItem->glyphPositions[i]);
1897 if (!verticalSubPixelPositions)
1898 subPixelPosition.y = 0;
1901 QTextureGlyphCache::GlyphAndSubPixelPosition glyph(staticTextItem->glyphs[i], subPixelPosition);
1903 const QTextureGlyphCache::Coord &c = cache->coords[glyph];
1907 int x = qFloor(staticTextItem->glyphPositions[i].x.toReal() * cache->transform().m11()) + c.baseLineX - margin;
1908 int y = verticalSubPixelPositions
1909 ? qRound(staticTextItem->glyphPositions[i].y.toReal() * cache->transform().m22())
1910 : qFloor(staticTextItem->glyphPositions[i].y.toReal() * cache->transform().m22());
1911 y -= c.baseLineY + margin;
1913 vertexCoordinates->addQuad(QRectF(x, y, c.w, c.h));
1914 textureCoordinates->addQuad(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy));
1917 staticTextItem->userDataNeedsUpdate =
false;
1920 int numGlyphs = vertexCoordinates->vertexCount() / 4;
1924 if (elementIndices.size() < numGlyphs*6) {
1925 Q_ASSERT(elementIndices.size() % 6 == 0);
1926 int j = elementIndices.size() / 6 * 4;
1927 while (j < numGlyphs*4) {
1928 elementIndices.append(j + 0);
1929 elementIndices.append(j + 0);
1930 elementIndices.append(j + 1);
1931 elementIndices.append(j + 2);
1932 elementIndices.append(j + 3);
1933 elementIndices.append(j + 3);
1938#if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO)
1939 if (elementIndicesVBOId == 0)
1940 funcs.glGenBuffers(1, &elementIndicesVBOId);
1942 funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementIndicesVBOId);
1943 funcs.glBufferData(GL_ELEMENT_ARRAY_BUFFER, elementIndices.size() *
sizeof(GLushort),
1944 elementIndices.constData(), GL_STATIC_DRAW);
1947#if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO)
1948 funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementIndicesVBOId);
1952 if (glyphFormat != QFontEngine::Format_ARGB || recreateVertexArrays) {
1953 uploadData(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinates->data(), vertexCoordinates->vertexCount() * 2);
1954 uploadData(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinates->data(), textureCoordinates->vertexCount() * 2);
1962 QBrush pensBrush = q->state()->pen.brush();
1963 setBrush(pensBrush);
1965 if (glyphFormat == QFontEngine::Format_A32) {
1969 QPainter::CompositionMode compMode = q->state()->composition_mode;
1970 Q_ASSERT(compMode == QPainter::CompositionMode_Source
1971 || compMode == QPainter::CompositionMode_SourceOver);
1973 shaderManager->setMaskType(QOpenGLEngineShaderManager::SubPixelMaskPass1);
1975 if (pensBrush.style() == Qt::SolidPattern) {
1977 QColor c = pensBrush.color();
1978 qreal oldOpacity = q->state()->opacity;
1979 if (compMode == QPainter::CompositionMode_Source) {
1980 c = qt_premultiplyColor(c, q->state()->opacity);
1981 q->state()->opacity = 1;
1986 prepareForCachedGlyphDraw(*cache);
1989 if (compMode == QPainter::CompositionMode_Source) {
1990 q->state()->opacity = oldOpacity;
1994 funcs.glEnable(GL_BLEND);
1995 funcs.glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR);
1996 funcs.glBlendColor(c.redF(), c.greenF(), c.blueF(), c.alphaF());
2000 qreal oldOpacity = q->state()->opacity;
2001 if (compMode == QPainter::CompositionMode_Source) {
2002 q->state()->opacity = 1;
2004 pensBrush = Qt::white;
2005 setBrush(pensBrush);
2009 prepareForCachedGlyphDraw(*cache);
2010 funcs.glEnable(GL_BLEND);
2011 funcs.glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
2015#if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO)
2016 funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, 0);
2018 const bool useIndexVbo = uploadIndexData(elementIndices.data(), GL_UNSIGNED_SHORT, 6 * numGlyphs);
2019 funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, useIndexVbo ?
nullptr : elementIndices.data());
2022 shaderManager->setMaskType(QOpenGLEngineShaderManager::SubPixelMaskPass2);
2024 if (compMode == QPainter::CompositionMode_Source) {
2025 q->state()->opacity = oldOpacity;
2027 pensBrush = q->state()->pen.brush();
2028 setBrush(pensBrush);
2032 prepareForCachedGlyphDraw(*cache);
2033 funcs.glEnable(GL_BLEND);
2034 funcs.glBlendFunc(GL_ONE, GL_ONE);
2037 }
else if (glyphFormat == QFontEngine::Format_ARGB) {
2038 currentBrush = noBrush;
2039 shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::ImageSrc);
2040 if (prepareForCachedGlyphDraw(*cache))
2041 shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::ImageTexture),
QT_IMAGE_TEXTURE_UNIT);
2045 shaderManager->setMaskType(QOpenGLEngineShaderManager::PixelMask);
2046 prepareForCachedGlyphDraw(*cache);
2050 if (glyphFormat == QFontEngine::Format_ARGB)
2053 QOpenGLTextureGlyphCache::FilterMode filterMode = (s->matrix.type() > QTransform::TxTranslate) ?
2054 QOpenGLTextureGlyphCache::Linear : QOpenGLTextureGlyphCache::Nearest;
2056 GLenum glFilterMode = filterMode == QOpenGLTextureGlyphCache::Linear ? GL_LINEAR : GL_NEAREST;
2059 if (cache->filterMode() != filterMode) {
2061 cache->setFilterMode(filterMode);
2064 updateTexture(textureUnit, cache->texture(), GL_REPEAT, glFilterMode, updateMode);
2066#if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO)
2067 funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, 0);
2068 funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
2070 const bool useIndexVbo = uploadIndexData(elementIndices.data(), GL_UNSIGNED_SHORT, 6 * numGlyphs);
2071 funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, useIndexVbo ?
nullptr : elementIndices.data());
2099 int fragmentCount,
const QPixmap &pixmap,
2100 QPainter::PixmapFragmentHints hints)
2102 GLfloat dx = 1.0f / pixmap.size().width();
2103 GLfloat dy = 1.0f / pixmap.size().height();
2105 vertexCoordinateArray.clear();
2106 textureCoordinateArray.clear();
2107 opacityArray.reset();
2114 bool allOpaque =
true;
2116 for (
int i = 0; i < fragmentCount; ++i) {
2119 if (fragments[i].rotation != 0) {
2120 s = qFastSin(qDegreesToRadians(fragments[i].rotation));
2121 c = qFastCos(qDegreesToRadians(fragments[i].rotation));
2124 qreal right = 0.5 * fragments[i].scaleX * fragments[i].width;
2125 qreal bottom = 0.5 * fragments[i].scaleY * fragments[i].height;
2126 QOpenGLPoint bottomRight(right * c - bottom * s, right * s + bottom * c);
2127 QOpenGLPoint bottomLeft(-right * c - bottom * s, -right * s + bottom * c);
2129 vertexCoordinateArray.addVertex(bottomRight.x + fragments[i].x, bottomRight.y + fragments[i].y);
2130 vertexCoordinateArray.addVertex(-bottomLeft.x + fragments[i].x, -bottomLeft.y + fragments[i].y);
2131 vertexCoordinateArray.addVertex(-bottomRight.x + fragments[i].x, -bottomRight.y + fragments[i].y);
2132 vertexCoordinateArray.addVertex(-bottomRight.x + fragments[i].x, -bottomRight.y + fragments[i].y);
2133 vertexCoordinateArray.addVertex(bottomLeft.x + fragments[i].x, bottomLeft.y + fragments[i].y);
2134 vertexCoordinateArray.addVertex(bottomRight.x + fragments[i].x, bottomRight.y + fragments[i].y);
2136 QOpenGLRect src(fragments[i].sourceLeft * dx, fragments[i].sourceTop * dy,
2137 (fragments[i].sourceLeft + fragments[i].width) * dx,
2138 (fragments[i].sourceTop + fragments[i].height) * dy);
2140 textureCoordinateArray.addVertex(src.right, src.bottom);
2141 textureCoordinateArray.addVertex(src.right, src.top);
2142 textureCoordinateArray.addVertex(src.left, src.top);
2143 textureCoordinateArray.addVertex(src.left, src.top);
2144 textureCoordinateArray.addVertex(src.left, src.bottom);
2145 textureCoordinateArray.addVertex(src.right, src.bottom);
2147 qreal opacity = fragments[i].opacity * q->state()->opacity;
2148 opacityArray << opacity << opacity << opacity << opacity << opacity << opacity;
2149 allOpaque &= (opacity >= 0.99f);
2154 uploadData(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data(), vertexCoordinateArray.vertexCount() * 2);
2155 uploadData(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data(), textureCoordinateArray.vertexCount() * 2);
2156 uploadData(QT_OPACITY_ATTR, (GLfloat*)opacityArray.data(), opacityArray.size());
2158 GLenum filterMode = q->state()->renderHints & QPainter::SmoothPixmapTransform ? GL_LINEAR : GL_NEAREST;
2161 bool isBitmap = pixmap.isQBitmap();
2162 bool isOpaque = !isBitmap && (!pixmap.hasAlpha() || (hints & QPainter::OpaqueHint)) && allOpaque;
2165 currentBrush = noBrush;
2166 shaderManager->setSrcPixelType(isBitmap ? QOpenGLEngineShaderManager::PatternSrc
2167 : QOpenGLEngineShaderManager::ImageSrc);
2168 if (prepareForDraw(isOpaque))
2169 shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::ImageTexture),
QT_IMAGE_TEXTURE_UNIT);
2172 QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity);
2173 shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::PatternColor), col);
2176 funcs.glDrawArrays(GL_TRIANGLES, 0, 6 * fragmentCount);
2179bool QOpenGL2PaintEngineEx::begin(QPaintDevice *pdev)
2181 Q_D(QOpenGL2PaintEngineEx);
2183 Q_ASSERT(pdev->devType() == QInternal::OpenGL);
2184 d->device =
static_cast<QOpenGLPaintDevice*>(pdev);
2189 d->device->ensureActiveTarget();
2191 if (d->device->context() != QOpenGLContext::currentContext() || !d->device->context()) {
2192 qWarning(
"QPainter::begin(): QOpenGLPaintDevice's context needs to be current");
2196 if (d->ctx != QOpenGLContext::currentContext()
2197 || (d->ctx && QOpenGLContext::currentContext() && d->ctx->format() != QOpenGLContext::currentContext()->format())) {
2198 d->vertexBuffer.destroy();
2199 d->texCoordBuffer.destroy();
2200 d->opacityBuffer.destroy();
2201 d->indexBuffer.destroy();
2205 d->ctx = QOpenGLContext::currentContext();
2206 d->ctx->d_func()->active_engine =
this;
2208 QOpenGLPaintDevicePrivate::get(d->device)->beginPaint();
2210 d->funcs.initializeOpenGLFunctions();
2218 const bool needsVAO = d->ctx->format().profile() == QSurfaceFormat::CoreProfile
2219 && d->ctx->format().version() >= std::pair(3, 2);
2220 if (needsVAO && !d->vao.isCreated()) {
2221 bool created = d->vao.create();
2229 if (!d->vertexBuffer.isCreated()) {
2230 d->vertexBuffer.create();
2232 d->vertexBuffer.setUsagePattern(QOpenGLBuffer::StreamDraw);
2234 if (!d->texCoordBuffer.isCreated()) {
2235 d->texCoordBuffer.create();
2236 d->texCoordBuffer.setUsagePattern(QOpenGLBuffer::StreamDraw);
2238 if (!d->opacityBuffer.isCreated()) {
2239 d->opacityBuffer.create();
2240 d->opacityBuffer.setUsagePattern(QOpenGLBuffer::StreamDraw);
2242 if (!d->indexBuffer.isCreated()) {
2243 d->indexBuffer.create();
2244 d->indexBuffer.setUsagePattern(QOpenGLBuffer::StreamDraw);
2248 d->vertexAttributeArraysEnabledState[i] =
false;
2250 const QSize sz = d->device->size();
2251 d->width = sz.width();
2252 d->height = sz.height();
2253 d->mode = BrushDrawingMode;
2254 d->brushTextureDirty =
true;
2255 d->brushUniformsDirty =
true;
2256 d->matrixUniformDirty =
true;
2257 d->matrixDirty =
true;
2258 d->compositionModeDirty =
true;
2259 d->opacityUniformDirty =
true;
2260 d->needsSync =
true;
2261 d->useSystemClip = !systemClip().isEmpty();
2262 d->currentBrush = QBrush();
2264 d->dirtyStencilRegion = QRect(0, 0, d->width, d->height);
2265 d->stencilClean =
true;
2267 d->shaderManager =
new QOpenGLEngineShaderManager(d->ctx);
2269 d->funcs.glDisable(GL_STENCIL_TEST);
2270 d->funcs.glDisable(GL_DEPTH_TEST);
2271 d->funcs.glDisable(GL_SCISSOR_TEST);
2273 d->glyphCacheFormat = QFontEngine::Format_A8;
2275#if !QT_CONFIG(opengles2)
2276 if (!QOpenGLContext::currentContext()->isOpenGLES()) {
2277 d->funcs.glDisable(GL_MULTISAMPLE);
2278 d->glyphCacheFormat = QFontEngine::Format_A32;
2279 d->multisamplingAlwaysEnabled =
false;
2285 d->multisamplingAlwaysEnabled = d->device->context()->format().samples() > 1;
2443 const bool singlePass = !path.hasWindingFill()
2444 && (((q->state()->currentClip == maxClip - 1) && q->state()->clipTestEnabled)
2445 || q->state()->needsClipBufferClear);
2446 const uint referenceClipValue = q->state()->needsClipBufferClear ? 1 : q->state()->currentClip;
2448 if (q->state()->needsClipBufferClear)
2451 if (path.isEmpty()) {
2452 funcs.glEnable(GL_STENCIL_TEST);
2457 if (q->state()->clipTestEnabled)
2460 funcs.glStencilFunc(GL_ALWAYS, 0, 0xff);
2462 vertexCoordinateArray.clear();
2463 vertexCoordinateArray.addPath(path, inverseScale,
false);
2466 fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill());
2468 funcs.glColorMask(
false,
false,
false,
false);
2469 funcs.glEnable(GL_STENCIL_TEST);
2477 funcs.glStencilOp(GL_KEEP, GL_INVERT, GL_INVERT);
2478 funcs.glStencilMask(value ^ referenceClipValue);
2480 drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN);
2482 funcs.glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
2483 funcs.glStencilMask(0xff);
2485 if (!q->state()->clipTestEnabled && path.hasWindingFill()) {
2488 composite(vertexCoordinateArray.boundingRect());
2494 composite(vertexCoordinateArray.boundingRect());
2498 funcs.glStencilMask(0);
2500 funcs.glColorMask(
true,
true,
true,
true);